﻿ /**
* @class StackedColumn3DLineDYChart
* @author InfoSoft Global (P) Ltd. www.InfoSoftGlobal.com
* @version 3.0
*
* Copyright (C) InfoSoft Global Pvt. Ltd. 2005-2006
*
* StackedColumn3DLineDYChart chart extends the DualYAxis3DChart class to render a
* Stacked 3D Column Chart + Multi-series Line Dual Y Combination Chart.
*/
//Import Chart class
import com.fusioncharts.core.Chart;
//Parent DualYAxis3DChart Class
import com.fusioncharts.core.DualYAxis3DChart;
//Error class
import com.fusioncharts.helper.FCError;
//Import Logger Class
import com.fusioncharts.helper.Logger;
//Style Object
import com.fusioncharts.core.StyleObject;
//Delegate
import mx.utils.Delegate;
//Legend Class
import com.fusioncharts.helper.Legend;
//Columns
import com.fusioncharts.core.chartobjects.Column3D;
//Extensions
import com.fusioncharts.extensions.ColorExt;
import com.fusioncharts.extensions.StringExt;
import com.fusioncharts.extensions.MathExt;
import com.fusioncharts.extensions.DrawingExt;
class com.fusioncharts.core.charts.StackedColumn3DLineDYChart extends DualYAxis3DChart 
{
	//Version number (if different from super Chart class)
	//private var _version:String = "3.0.0";
	//Instance variables
	//List of chart objects
	private var _arrObjects : Array;
	private var xmlData : XML;
	//Array to store x-axis categories (labels)
	private var categories : Array;
	//Array to store datasets
	private var dataset : Array;
	//Number of data sets
	private var numDS : Number;
	//Number of column and line datasets
	private var numColDS : Number;
	private var numLineDS : Number;
	//Number of data items
	private var num : Number;
	//Reference to legend component of chart
	private var lgnd : Legend;
	//Reference to legend movie clip
	private var lgndMC : MovieClip;
	//Flag to indicate whether positive number is present
	private var positivePresent : Boolean;
	//Flag to indicate whether negative number is present
	private var negativePresent : Boolean;
	//Array to store Sums
	private var sums : Array;
	private var sumStored : Boolean;
	/**
	* Constructor function. We invoke the super class'
	* constructor and then set the objects for this chart.
	*/
	function StackedColumn3DLineDYChart (targetMC : MovieClip, depth : Number, width : Number, height : Number, x : Number, y : Number, debugMode : Boolean, lang : String)
	{
		//Invoke the super class constructor
		super (targetMC, depth, width, height, x, y, debugMode, lang);
		//Log additional information to debugger
		//We log version from this class, so that if this class version
		//is different, we can log it
		this.log ("Version", _version, Logger.LEVEL.INFO);
		this.log ("Chart Type", "Stacked 3D Column + Line Dual Y Combination Chart", Logger.LEVEL.INFO);
		//List Chart Objects and set them
		_arrObjects = new Array ("BACKGROUND", "CANVAS", "CAPTION", "SUBCAPTION", "YAXISNAME", "XAXISNAME", "DIVLINES", "YAXISVALUES", "DATALABELS", "DATAVALUES", "TRENDLINES", "TRENDVALUES", "DATAPLOTCOLUMN", "DATAPLOTLINE", "ANCHORS", "TOOLTIP", "VLINES", "LEGEND");
		super.setChartObjects (_arrObjects);
		//Initialize the containers for chart
		this.categories = new Array ();
		this.dataset = new Array ();
		//Initialize the number of data elements present
		this.numDS = 0;
		this.numColDS = 0;
		this.numLineDS = 0;
		this.num = 0;
		this.negativePresent = false;
		this.positivePresent = false;
		//Array to store sum of data sets
		this.sums = new Array ();
		this.sumStored = false;
	}
	/**
	* render method is the single call method that does the rendering of chart:
	* - Parsing XML
	* - Calculating values and co-ordinates
	* - Visual layout and rendering
	* - Event handling
	*/
	public function render () : Void 
	{
		//Parse the XML Data document
		this.parseXML ();
		//Now, if the number of data elements is 0, we show pertinent
		//error.
		if (this.numColDS * this.num == 0)
		{
			tfAppMsg = this.renderAppMessage (_global.getAppMessage ("NODATA", this.lang));
			//Add a message to log.
			this.log ("No Data to Display", "No data was found in the XML data document provided. Possible cases can be: <LI>There isn't any data generated by your system. If your system generates data based on parameters passed to it using dataURL, please make sure dataURL is URL Encoded.</LI><LI>You might be using a Single Series Chart .swf file instead of Multi-series .swf file and providing multi-series data or vice-versa.</LI>", Logger.LEVEL.ERROR);
		} else 
		{
			//Detect number scales
			this.detectNumberScales ();
			//Calculate the axis limits
			this.calculateAxisLimits ();
			//Calculate exact number of div lines
			this.calcDivs ();
			//Set Style defaults
			this.setStyleDefaults ();
			//Validate trend lines
			this.validateTrendLines ();
			//Allot the depths for various charts objects now
			this.allotDepths ();
			//Calculate Points
			this.calculatePoints ();
			//Calculate vLine Positions
			this.calcVLinesPos ();
			//Calculate trend line positions
			this.calcTrendLinePos ();
			//Feed macro values
			this.feedMacros ();
			//Remove application message
			this.removeAppMessage (this.tfAppMsg);
			//Set tool tip parameter
			this.setToolTipParam ();
			//-----Start Visual Rendering Now------//
			//Draw background
			this.drawBackground ();
			//Set click handler
			this.drawClickURLHandler ()
			//Load background SWF
			this.loadBgSWF ();
			//Update timer
			this.timeElapsed = (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.BACKGROUND) : 0;
			//Draw canvas
			this.config.intervals.canvas = setInterval (Delegate.create (this, drawCanvas) , this.timeElapsed);
			//Draw headers
			this.config.intervals.headers = setInterval (Delegate.create (this, drawHeaders) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.CANVAS, this.objects.CAPTION, this.objects.SUBCAPTION, this.objects.YAXISNAME, this.objects.XAXISNAME) : 0;
			//Draw div lines
			this.config.intervals.divLines = setInterval (Delegate.create (this, drawDivLines) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.DIVLINES, this.objects.YAXISVALUES) : 0;
			//Draw labels
			this.config.intervals.labels = setInterval (Delegate.create (this, drawLabels) , this.timeElapsed);
			//Draw columns
			this.config.intervals.plot = setInterval (Delegate.create (this, drawColumns) , this.timeElapsed);
			//Legend
			this.config.intervals.legend = setInterval (Delegate.create (this, drawLegend) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.DATALABELS, this.objects.DATAPLOTCOLUMN, this.objects.LEGEND) : 0;
			if (this.numLineDS > 0)
			{
				//Draw Lines - if required
				this.config.intervals.plotLine = setInterval (Delegate.create (this, drawLineChart) , this.timeElapsed);
				//Update timer
				this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.DATAPLOTLINE) : 0;
			}
			//Anchors
			this.config.intervals.anchors = setInterval (Delegate.create (this, drawAnchors) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.ANCHORS) : 0;
			//Line values
			this.config.intervals.dataValuesLine = setInterval (Delegate.create (this, drawLineValues) , this.timeElapsed);
			//Data Values
			this.config.intervals.dataValues = setInterval (Delegate.create (this, drawColumnValues) , this.timeElapsed);
			//Data Sum
			this.config.intervals.dataSum = setInterval (Delegate.create (this, drawSum) , this.timeElapsed);
			//Draw trend lines
			this.config.intervals.trend = setInterval (Delegate.create (this, drawTrendLines) , this.timeElapsed);
			//Draw vertical div lines
			this.config.intervals.vLine = setInterval (Delegate.create (this, drawVLines) , this.timeElapsed);
			//Update timer
			this.timeElapsed += (this.params.animation) ? this.styleM.getMaxAnimationTime (this.objects.TRENDLINES, this.objects.TRENDVALUES, this.objects.VLINES, this.objects.DATAVALUES) : 0;
			//Render context menu
			//We do not put context menu interval as we need the menu to appear
			//right from start of the play.
			this.setContextMenu ();
		}
	}
	/**
	* returnDataAsObject method creates an object out of the parameters
	* passed to this method. The idea is that we store each data point
	* as an object with multiple (flexible) properties. So, we do not
	* use a predefined class structure. Instead we use a generic object.
	*	@param	value		Value for the data.
	*	@param	color		Hex Color code.
	*	@param	alpha		Alpha of the line
	*	@param	toolText	Tool tip text (if specified).
	*	@param	link		Link (if any) for the data.
	*	@param	showValue	Flag to show/hide value for this data.
	*	@param	isDashed	Flag whether the line would be dashed.
	*	@param	anchorSides				Number of sides of the anchor.
	*	@param	anchorRadius			Radius of the anchor (in pixels).
	*	@param	anchorBorderColor		Border color of the anchor.
	*	@param	anchorBorderThickness	Border thickness of the anchor.
	*	@param	anchorBgColor			Background color of the anchor.
	*	@param	anchorAlpha				Alpha of the anchor.
	*	@param	anchorBgAlpha			Background (fill) alpha of the anchor.
	*	@return			An object encapsulating all these properies.
	*/
	private function returnDataAsObject (value : Number, color : String, alpha : Number, toolText : String, link : String, showValue : Number, isDashed : Boolean, anchorSides : Number, anchorRadius : Number, anchorBorderColor : String, anchorBorderThickness : Number, anchorBgColor : String, anchorAlpha : Number, anchorBgAlpha : Number) : Object 
	{
		//Create a container
		var dataObj : Object = new Object ();
		//Store the values
		dataObj.value = value;
		dataObj.color = color;
		dataObj.alpha = alpha;
		dataObj.toolText = toolText;
		dataObj.link = link;
		dataObj.showValue = (showValue == 1) ? true : false;
		dataObj.dashed = isDashed;
		//Anchor properties
		dataObj.anchorSides = anchorSides;
		dataObj.anchorRadius = anchorRadius;
		dataObj.anchorBorderColor = anchorBorderColor;
		dataObj.anchorBorderThickness = anchorBorderThickness;
		dataObj.anchorBgColor = anchorBgColor;
		dataObj.anchorAlpha = anchorAlpha;
		dataObj.anchorBgAlpha = anchorBgAlpha;
		//If the given number is not a valid number or it's missing
		//set appropriate flags for this data point
		dataObj.isDefined = ((dataObj.alpha == 0) || isNaN (value)) ? false : true;
		//Other parameters
		//X & Y Position of data point
		dataObj.x = 0;
		dataObj.y = 0;
		//X & Y Position of value tb
		dataObj.valTBX = 0;
		dataObj.valTBY = 0;
		//Return the container
		return dataObj;
	}
	/**
	* returnDataAsCat method returns data of a <category> element as
	* an object
	*	@param	label		Label of the category.
	*	@param	showLabel	Whether to show the label of this category.
	*	@param	toolText	Tool-text for the category
	*	@return			A container object with the given properties
	*/
	private function returnDataAsCat (label : String, showLabel : Number, toolText : String) : Object
	{
		//Create container object
		var catObj : Object = new Object ();
		catObj.label = label;
		catObj.showLabel = ((showLabel == 1) && (label != undefined) && (label != null) && (label != "")) ? true : false;
		catObj.toolText = toolText;
		//X and Y Position
		catObj.x = 0;
		catObj.y = 0;
		//Return container
		return catObj;
	}
	/**
	* parseXML method parses the XML data, sets defaults and validates
	* the attributes before storing them to data storage objects.
	*/
	private function parseXML () : Void 
	{
		//Get the element nodes
		var arrDocElement : Array = this.xmlData.childNodes;
		//Loop variable
		var i : Number;
		var j : Number;
		var k : Number;
		//Look for <graph> element
		for (i = 0; i < arrDocElement.length; i ++)
		{
			//If it's a <graph> element, proceed.
			//Do case in-sensitive mathcing by changing to upper case
			if (arrDocElement [i].nodeName.toUpperCase () == "GRAPH" || arrDocElement [i].nodeName.toUpperCase () == "CHART")
			{
				//Extract attributes of <graph> element
				this.parseAttributes (arrDocElement [i]);
				//Now, get the child nodes - first level nodes
				//Level 1 nodes can be - CATEGORIES, DATASET, TRENDLINES, STYLES etc.
				var arrLevel1Nodes : Array = arrDocElement [i].childNodes;
				var setNode : XMLNode;
				//Iterate through all level 1 nodes.
				for (j = 0; j < arrLevel1Nodes.length; j ++)
				{
					if (arrLevel1Nodes [j].nodeName.toUpperCase () == "CATEGORIES")
					{
						//Categories Node.
						var categoriesNode : XMLNode = arrLevel1Nodes [j];
						//Convert attributes to array
						var categoriesAtt : Array = this.getAttributesArray (categoriesNode);
						//Extract attributes of this node.
						this.params.catFont = getFV (categoriesAtt ["font"] , this.params.outCnvBaseFont);
						this.params.catFontSize = getFN (categoriesAtt ["fontsize"] , this.params.outCnvBaseFontSize);
						this.params.catFontColor = formatColor (getFV (categoriesAtt ["fontcolor"] , this.params.outCnvBaseFontColor));
						//Get reference to child node.
						var arrLevel2Nodes : Array = arrLevel1Nodes [j].childNodes;
						//Iterate through all child-nodes of CATEGORIES element
						//and search for CATEGORY or VLINE node
						for (k = 0; k < arrLevel2Nodes.length; k ++)
						{
							if (arrLevel2Nodes [k].nodeName.toUpperCase () == "CATEGORY")
							{
								//Category Node.
								//Update counter
								this.num ++;
								//Extract attributes
								var categoryNode : XMLNode = arrLevel2Nodes [k];
								var categoryAtt : Array = this.getAttributesArray (categoryNode);
								//Category label.
								var catLabel : String = getFV (categoryAtt ["label"] , categoryAtt ["name"] , "");
								var catShowLabel : Number = getFN (categoryAtt ["showlabel"] , categoryAtt ["showname"] , this.params.showLabels);
								var catToolText : String = getFV (categoryAtt ["tooltext"] , categoryAtt ["hovertext"] , catLabel);
								//Store it in data container.
								this.categories [this.num] = this.returnDataAsCat (catLabel, catShowLabel, catToolText);
							} 
							else if (arrLevel2Nodes [k].nodeName.toUpperCase () == "VLINE")
							{
								//Vertical axis division Node - extract child nodes
								var vLineNode : XMLNode = arrLevel2Nodes [k];
								//Parse and store
								this.parseVLineNode (vLineNode, this.num);
							}
						}
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "DATASET")
					{
						//Increment
						this.numDS ++;
						//Dataset node.
						var dataSetNode : XMLNode = arrLevel1Nodes [j];
						//Get attributes array
						var dsAtts : Array = this.getAttributesArray (dataSetNode);
						//Create storage object in dataset array
						this.dataset [this.numDS] = new Object ();
						//Parent y-axis
						this.dataset [this.numDS].parentYAxis = getFV (dsAtts ["parentyaxis"] , "P");
						//Capitalize
						this.dataset [this.numDS].parentYAxis = this.dataset [this.numDS].parentYAxis.toUpperCase ();
						//Parent y-axis can either be P or S - Defaults to P
						if (this.dataset [this.numDS].parentYAxis != "P" && this.dataset [this.numDS].parentYAxis != "S")
						{
							this.dataset [this.numDS].parentYAxis = "P";
						}
						//Update dataset counter based on what the dataset is to be rendered as.
						switch (this.dataset [this.numDS].parentYAxis)
						{
							case "P" :
							this.numColDS ++;
							break;
							case "S" :
							this.numLineDS ++;
							break;
						}
						//Store attributes
						this.dataset [this.numDS].seriesName = getFV (dsAtts ["seriesname"] , "");
						this.dataset [this.numDS].color = getFV (dsAtts ["color"] , this.defColors.getColor ());
						this.dataset [this.numDS].alpha = getFN (dsAtts ["alpha"] , this.params.plotFillAlpha);
						this.dataset [this.numDS].showValues = toBoolean (getFN (dsAtts ["showvalues"] , this.params.showValues));
						this.dataset [this.numDS].includeInLegend = toBoolean (getFN (dsAtts ["includeinlegend"] , 1));
						//Line dash properties
						this.dataset [this.numDS].dashed = toBoolean (getFN (dsAtts ["dashed"] , this.params.lineDashed));
						this.dataset [this.numDS].lineDashLen = getFN (dsAtts ["linedashlen"] , this.params.lineDashLen);
						this.dataset [this.numDS].lineDashGap = getFN (dsAtts ["linedashgap"] , this.params.lineDashGap);
						this.dataset [this.numDS].lineThickness = getFN (dsAtts ["linethickness"] , this.params.lineThickness);
						//Data set anchors
						this.dataset [this.numDS].drawAnchors = toBoolean (getFN (dsAtts ["drawanchors"] , dsAtts ["showanchors"] , this.params.drawAnchors));
						this.dataset [this.numDS].anchorSides = getFN (dsAtts ["anchorsides"] , this.params.anchorSides);
						this.dataset [this.numDS].anchorRadius = getFN (dsAtts ["anchorradius"] , this.params.anchorRadius);
						this.dataset [this.numDS].anchorBorderColor = formatColor (getFV (dsAtts ["anchorbordercolor"] , this.params.anchorBorderColor, this.dataset [this.numDS].color));
						this.dataset [this.numDS].anchorBorderThickness = getFN (dsAtts ["anchorborderthickness"] , this.params.anchorBorderThickness);
						this.dataset [this.numDS].anchorBgColor = formatColor (getFV (dsAtts ["anchorbgcolor"] , this.params.anchorBgColor));
						this.dataset [this.numDS].anchorAlpha = getFN (dsAtts ["anchoralpha"] , this.params.anchorAlpha);
						this.dataset [this.numDS].anchorBgAlpha = getFN (dsAtts ["anchorbgalpha"] , this.params.anchorBgAlpha);
						//Create data array under it.
						this.dataset [this.numDS].data = new Array ();
						//Get reference to child node.
						var arrLevel2Nodes : Array = arrLevel1Nodes [j].childNodes;
						//Iterate through all child-nodes of DATASET element
						//and search for SET node
						//Counter
						var setCount : Number = 0;
						for (k = 0; k < arrLevel2Nodes.length; k ++)
						{
							if (arrLevel2Nodes [k].nodeName.toUpperCase () == "SET")
							{
								//Set Node. So extract the data.
								//Update counter
								setCount ++;
								//Get reference to node.
								setNode = arrLevel2Nodes [k];
								//Get attributes
								var atts : Array;
								atts = this.getAttributesArray (setNode);
								//Now, get value.
								var setValue : Number = this.getSetValue (atts ["value"]);
								//We do NOT unescape the link, as this will be done
								//in invokeLink method for the links that user clicks.
								var setLink : String = getFV (atts ["link"] , "");
								var setToolText : String = getFV (atts ["tooltext"] , atts ["hovertext"]);
								var setColor : String = getFV (atts ["color"] , this.dataset [this.numDS].color);
								var setAlpha : Number = getFN (atts ["alpha"] , this.dataset [this.numDS].alpha);
								var setShowValue : Number = getFN (atts ["showvalue"] , this.dataset [this.numDS].showValues);
								var setDashed : Boolean = toBoolean (getFN (atts ["dashed"] , this.dataset [this.numDS].dashed));
								//Anchor properties for individual set
								var setAnchorSides : Number = getFN (atts ["anchorsides"] , this.dataset [this.numDS].anchorSides);
								var setAnchorRadius : Number = getFN (atts ["anchorradius"] , this.dataset [this.numDS].anchorRadius);
								var setAnchorBorderColor : String = formatColor (getFV (atts ["anchorbordercolor"] , this.dataset [this.numDS].anchorBorderColor));
								var setAnchorBorderThickness : Number = getFN (atts ["anchorborderthickness"] , this.dataset [this.numDS].anchorBorderThickness);
								var setAnchorBgColor : String = formatColor (getFV (atts ["anchorbgcolor"] , this.dataset [this.numDS].anchorBgColor));
								var setAnchorAlpha : Number = getFN (atts ["anchoralpha"] , this.dataset [this.numDS].anchorAlpha);
								var setAnchorBgAlpha : Number = getFN (atts ["anchorbgalpha"] , this.dataset [this.numDS].anchorBgAlpha);
								//Store all these attributes as object.
								this.dataset [this.numDS].data [setCount] = this.returnDataAsObject (setValue, setColor, setAlpha, setToolText, setLink, setShowValue, setDashed, setAnchorSides, setAnchorRadius, setAnchorBorderColor, setAnchorBorderThickness, setAnchorBgColor, setAnchorAlpha, setAnchorBgAlpha);
								//Update numNeg, numPos based on set value
								if (setValue < 0)
								{
									//Update negative count
									numNeg ++;
								}else
								{
									//Update positive count
									numPos ++;
								}
								//Update negative flag
								this.negativePresent = (setValue < 0) ?true : negativePresent;
								this.positivePresent = (setValue >= 0) ?true : positivePresent;
							}
						}
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "STYLES")
					{
						//Styles Node - extract child nodes
						var arrStyleNodes : Array = arrLevel1Nodes [j].childNodes;
						//Parse the style nodes to extract style information
						super.parseStyleXML (arrStyleNodes);
					} else if (arrLevel1Nodes [j].nodeName.toUpperCase () == "TRENDLINES")
					{
						//Trend lines node
						var arrTrendNodes : Array = arrLevel1Nodes [j].childNodes;
						//Parse the trend line nodes
						super.parseTrendLineXML (arrTrendNodes);
					}
				}
			}
		}
		//Delete all temporary objects used for parsing XML Data document
		delete setNode;
		delete arrDocElement;
		delete arrLevel1Nodes;
		delete arrLevel2Nodes;
	}
	/**
	* parseAttributes method parses the attributes and stores them in
	* chart storage objects.
	* Starting ActionScript 2, the parsing of XML attributes have also
	* become case-sensitive. However, prior versions of FusionCharts
	* supported case-insensitive attributes. So we need to parse all
	* attributes as case-insensitive to maintain backward compatibility.
	* To do so, we first extract all attributes from XML, convert it into
	* lower case and then store it in an array. Later, we extract value from
	* this array.
	* @param	graphElement	XML Node containing the <graph> element
	*							and it's attributes
	*/
	private function parseAttributes (graphElement : XMLNode) : Void 
	{
		//Array to store the attributes
		var atts : Array = this.getAttributesArray (graphElement);
		//NOW IT'S VERY NECCESARY THAT WHEN WE REFERENCE THIS ARRAY
		//TO GET AN ATTRIBUTE VALUE, WE SHOULD PROVIDE THE ATTRIBUTE
		//NAME IN LOWER CASE. ELSE, UNDEFINED VALUE WOULD SHOW UP.
		//Extract attributes pertinent to this chart
		//Which palette to use?
		this.params.palette = getFN (atts ["palette"] , 1)
		//Whether to show about FusionCharts Menu Item - by default set to on
		this.params.showFCMenuItem = toBoolean(getFN (atts ["showfcmenuitem"] , 1));
		// ---------- PADDING AND SPACING RELATED ATTRIBUTES ----------- //
		//captionPadding = Space between caption/subcaption and canvas start Y
		this.params.captionPadding = getFN (atts ["captionpadding"] , 10);
		//canvasPadding - Padding on the canvas on left and right side of column
		this.params.canvasPadding = getFN (atts ["canvaspadding"] , 10);
		//Padding for x-axis name - to the right
		this.params.xAxisNamePadding = getFN (atts ["xaxisnamepadding"] , 5);
		//Padding for y-axis name - from top
		this.params.yAxisNamePadding = getFN (atts ["yaxisnamepadding"] , 5);
		//Y-Axis Values padding - Horizontal space between the axis edge and
		//y-axis values or trend line values (on left/right side).
		this.params.yAxisValuesPadding = getFN (atts ["yaxisvaluespadding"] , 2);
		//Label padding - Vertical space between the labels and canvas end position
		this.params.labelPadding = getFN (atts ["labelpadding"] , atts ["labelspadding"] , 3);
		//Value padding - vertical space between the end of columns and start of value textboxes
		this.params.valuePadding = getFN (atts ["valuepadding"] , 2);
		//Percentage space on the plot area
		this.params.plotSpacePercent = getFN (atts ["plotspacepercent"] , 20);
		///Cannot be less than 0 and more than 80
		if ((this.params.plotSpacePercent < 0) || (this.params.plotSpacePercent > 80))
		{
			//Reset to 20
			this.params.plotSpacePercent = 20;
		}
		//Padding of legend from right/bottom side of canvas
		this.params.legendPadding = getFN (atts ["legendpadding"] , 6);
		//Chart Margins - Empty space at the 4 sides
		this.params.chartLeftMargin = getFN (atts ["chartleftmargin"] , 15);
		this.params.chartRightMargin = getFN (atts ["chartrightmargin"] , 15);
		this.params.chartTopMargin = getFN (atts ["charttopmargin"] , 15);
		this.params.chartBottomMargin = getFN (atts ["chartbottommargin"] , 15);
		// -------------------------- HEADERS ------------------------- //
		//Chart Caption and sub Caption
		this.params.caption = getFV (atts ["caption"] , "");
		this.params.subCaption = getFV (atts ["subcaption"] , "");
		//X and Y Axis Name
		this.params.xAxisName = getFV (atts ["xaxisname"] , "");
		this.params.PYAxisName = getFV (atts ["pyaxisname"] , "");
		this.params.SYAxisName = getFV (atts ["syaxisname"] , "");
		//Adaptive yMin - if set to true, the y min will be based on the values
		//provided. It won't be set to 0 in case of all positive values
		this.params.setAdaptiveSYMin = toBoolean (getFN (atts ["setadaptivesymin"] , (this.params.setAdaptiveYMin) ?1 : 0));
		// --------------------- CONFIGURATION ------------------------- //
		//The upper and lower limits of y and x axis
		//In a stacked column chart, users cannot set yAxisMinValue as it always
		//emanates from 0.
		//The upper and lower limits of y and x axis
		this.params.PYAxisMaxValue = atts ["pyaxismaxvalue"];
		this.params.SYAxisMinValue = atts ["syaxisminvalue"];
		this.params.SYAxisMaxValue = atts ["syaxismaxvalue"];
		//Whether to set animation for entire chart.
		this.params.animation = toBoolean (getFN (atts ["animation"] , 1));
		//Whether to set the default chart animation
		this.params.defaultAnimation = toBoolean (getFN (atts ["defaultanimation"] , 1));
		//Whether null data points are to be connected or left broken
		this.params.connectNullData = toBoolean (getFN (atts ["connectnulldata"] , 0));
		//Whether to overlap columns
		this.params.overlapColumns = atts ["overlapcolumns"];
		//Maximum allowed column width
		this.params.maxColWidth = getFN (atts ["maxcolwidth"] , 100);
		//Configuration to set whether to show the labels
		this.params.showLabels = toBoolean (getFN (atts ["showlabels"] , atts ["shownames"] , 1));
		//Label Display Mode - WRAP, STAGGER, ROTATE or NONE
		this.params.labelDisplay = getFV (atts ["labeldisplay"] , "WRAP");
		//Remove spaces and capitalize
		this.params.labelDisplay = StringExt.removeSpaces (this.params.labelDisplay);
		this.params.labelDisplay = this.params.labelDisplay.toUpperCase ();
		//Option to show vertical x-axis labels
		this.params.rotateLabels = getFV (atts ["rotatelabels"] , atts ["rotatenames"]);
		//Whether to slant label (if rotated)
		this.params.slantLabels = toBoolean (getFN (atts ["slantlabels"] , atts ["slantlabel"] , 0));
		//Angle of rotation based on slanting
		this.config.labelAngle = (this.params.slantLabels == true) ? 315 : 270;
		//If rotateLabels has been explicitly specified, we assign ROTATE value to this.params.labelDisplay
		this.params.labelDisplay = (this.params.rotateLabels == "1") ? "ROTATE" : this.params.labelDisplay;
		//Step value for labels - i.e., show all labels or skip every x label
		this.params.labelStep = int (getFN (atts ["labelstep"] , 1));
		//Cannot be less than 1
		this.params.labelStep = (this.params.labelStep < 1) ? 1 : this.params.labelStep;
		//Number of stagger lines
		this.params.staggerLines = int (getFN (atts ["staggerlines"] , 2));
		//Cannot be less than 2
		this.params.staggerLines = (this.params.staggerLines < 2) ? 2 : this.params.staggerLines;
		//Configuration whether to show data values
		this.params.showValues = toBoolean (getFN (atts ["showvalues"] , 1));
		//Configuration whether to show data sum
		this.params.showSum = toBoolean (getFN (atts ["showsum"] , 0));
		//Whether to rotate values
		this.params.rotateValues = toBoolean (getFN (atts ["rotatevalues"] , 0));
		//Option to show/hide y-axis values
		this.params.showYAxisValues = getFN (atts ["showyaxisvalues"] , atts ["showyaxisvalue"] , 1);
		this.params.showLimits = toBoolean (getFN (atts ["showlimits"] , this.params.showYAxisValues));
		this.params.showDivLineValues = toBoolean (getFN (atts ["showdivlinevalue"] , atts ["showdivlinevalues"] , this.params.showYAxisValues));
		//Secondary axis limits and div line values
		this.params.showSecondaryLimits = toBoolean (getFN (atts ["showsecondarylimits"] , this.params.showLimits));
		this.params.showDivLineSecondaryValue = toBoolean (getFN (atts ["showdivlinesecondaryvalue"] , this.params.showYAxisValues));
		//Y-axis value step- i.e., show all y-axis or skip every x(th) value
		this.params.yAxisValuesStep = int (getFN (atts ["yaxisvaluesstep"] , atts ["yaxisvaluestep"] , 1));
		//Cannot be less than 1
		this.params.yAxisValuesStep = (this.params.yAxisValuesStep < 1) ? 1 : this.params.yAxisValuesStep;
		//Whether to automatically adjust div lines
		this.params.adjustDiv = toBoolean (getFN (atts ["adjustdiv"] , 1));
		//Whether to rotate y-axis name
		this.params.rotateYAxisName = toBoolean (getFN (atts ["rotateyaxisname"] , 1));
		//Max width to be alloted to y-axis name - No defaults, as it's calculated later.
		this.params.PYAxisNameWidth = atts ["pyaxisnamewidth"];
		this.params.SYAxisNameWidth = atts ["syaxisnamewidth"];
		//Column Depth
		this.params.columnDepth = getFN (atts ["columndepth"] , - 1)
		//Click URL
		this.params.clickURL = getFV (atts ["clickurl"] , "");
		// ------------------------- COSMETICS -----------------------------//
		//Whether to use 3D Lighting
		this.params.use3DLighting = toBoolean (getFN (atts ["use3dlighting"] , 1));
		//Show shadow
		this.params.showShadow = toBoolean (getFN (atts ["showshadow"] , atts ["showcolumnshadow"] , (this.params.use3DLighting) ?1 : 0));
		//Background properties - Gradient
		this.params.bgColor = getFV (atts ["bgcolor"] , this.defColors.getBgColor3D (this.params.palette));
		this.params.bgAlpha = getFV (atts ["bgalpha"] , this.defColors.getBgAlpha3D (this.params.palette));
		this.params.bgRatio = getFV (atts ["bgratio"] , this.defColors.getBgRatio3D (this.params.palette));
		this.params.bgAngle = getFV (atts ["bgangle"] , this.defColors.getBgAngle3D (this.params.palette));
		//Border Properties of chart
		this.params.showBorder = toBoolean (getFN (atts ["showborder"] , 0));
		this.params.borderColor = formatColor (getFV (atts ["bordercolor"] , "666666"));
		this.params.borderThickness = getFN (atts ["borderthickness"] , 1);
		this.params.borderAlpha = getFN (atts ["borderalpha"] , 100);
		//Background swf
		this.params.bgSWF = getFV (atts ["bgswf"] , "");
		this.params.bgSWFAlpha = getFN (atts ["bgswfalpha"] , 100);
		//Canvas background properties
		this.params.canvasBgColor = formatColor (getFV (atts ["canvasbgcolor"] , this.defColors.getCanvasBgColor3D (this.params.palette)));
		this.params.canvasBgAlpha = getFN (atts ["canvasbgalpha"] , 100);
		this.params.canvasBaseColor = formatColor (getFV (atts ["canvasbasecolor"] , this.defColors.getCanvasBaseColor3D (this.params.palette)));
		//Option to show/hide canvas base and bg
		this.params.showCanvasBg = toBoolean (getFN (atts ["showcanvasbg"] , 1));
		this.params.showCanvasBase = toBoolean (getFN (atts ["showcanvasbase"] , 1));
		//Depth of background and base
		this.params.canvasBaseDepth = getFN (atts ["canvasbasedepth"] , 10);
		this.params.canvasBgDepth = getFN (atts ["canvasbgdepth"] , 3);
		//Plot cosmetic properties
		this.params.showPlotBorder = toBoolean (getFN (atts ["showplotborder"] , 0));
		this.params.plotBorderColor = formatColor (getFV (atts ["plotbordercolor"] , "FFFFFF"));
		this.params.plotBorderAlpha = getFN (atts ["plotborderalpha"] , (this.params.showPlotBorder == true) ?95 : 0);
		//Fill properties
		this.params.plotFillAlpha = getFN (atts ["plotfillalpha"] , 100);
		//Legend properties
		this.params.showLegend = toBoolean (getFN (atts ["showlegend"] , 1));
		//Alignment position
		this.params.legendPosition = getFV (atts ["legendposition"] , "BOTTOM");
		//Legend position can be either RIGHT or BOTTOM -Check for it
		this.params.legendPosition = (this.params.legendPosition.toUpperCase () == "RIGHT") ?"RIGHT" : "BOTTOM";
		this.params.legendBorderColor = formatColor (getFV (atts ["legendbordercolor"] , this.defColors.getLegendBorderColor3D (this.params.palette)));
		this.params.legendBorderThickness = getFN (atts ["legendborderthickness"] , 1);
		this.params.legendBorderAlpha = getFN (atts ["legendborderalpha"] , 100);
		this.params.legendBgColor = getFV (atts ["legendbgcolor"] , this.defColors.getLegendBgColor3D (this.params.palette));
		this.params.legendBgAlpha = getFN (atts ["legendbgalpha"] , 100);
		this.params.legendShadow = toBoolean (getFN (atts ["legendshadow"] , 1));
		this.params.legendAllowDrag = toBoolean (getFN (atts ["legendallowdrag"] , 0));
		this.params.legendScrollBgColor = formatColor (getFV (atts ["legendscrollbgcolor"] , "CCCCCC"));
		this.params.legendScrollBarColor = formatColor (getFV (atts ["legendscrollbarcolor"] , this.params.legendBorderColor));
		this.params.legendScrollBtnColor = formatColor (getFV (atts ["legendscrollbtncolor"] , this.params.legendBorderColor));
		//Horizontal grid division Lines - Number, color, thickness & alpha
		//Necessarily need a default value for numDivLines.
		this.params.numDivLines = getFN (atts ["numdivlines"] , 4);
		this.params.divLineColor = formatColor (getFV (atts ["divlinecolor"] , this.defColors.getDivLineColor3D (this.params.palette)));
		this.params.divLineThickness = getFN (atts ["divlinethickness"] , 1);
		this.params.divLineAlpha = getFN (atts ["divlinealpha"] , 100);
		this.params.divLineIsDashed = toBoolean (getFN (atts ["divlineisdashed"] , 0));
		this.params.divLineDashLen = getFN (atts ["divlinedashlen"] , 4);
		this.params.divLineDashGap = getFN (atts ["divlinedashgap"] , 2);
		//Line Properties
		this.params.lineColor = atts ["linecolor"];
		this.params.lineThickness = getFN (atts ["linethickness"] , 3);
		this.params.lineAlpha = getFN (atts ["linealpha"] , 100);
		this.params.lineDashed = toBoolean (getFN (atts ["linedashed"] , 0));
		this.params.lineDashLen = getFN (atts ["linedashlen"] , 5);
		this.params.lineDashGap = getFN (atts ["linedashgap"] , 4);
		//Anchor Properties
		this.params.drawAnchors = toBoolean (getFN (atts ["drawanchors"] , atts ["showanchors"] , 1));
		this.params.anchorSides = getFN (atts ["anchorsides"] , 10);
		this.params.anchorRadius = getFN (atts ["anchorradius"] , 3);
		this.params.anchorBorderColor = atts ["anchorbordercolor"];
		this.params.anchorBorderThickness = getFN (atts ["anchorborderthickness"] , 1);
		this.params.anchorBgColor = formatColor (getFV (atts ["anchorbgcolor"] , this.defColors.getAnchorBgColor3D (this.params.palette)));
		this.params.anchorAlpha = getFN (atts ["anchoralpha"] , 100);
		this.params.anchorBgAlpha = getFN (atts ["anchorbgalpha"] , this.params.anchorAlpha);
		//Zero Plane properties
		this.params.showZeroPlane = true;
		this.params.zeroPlaneColor = formatColor (getFV (atts ["zeroplanecolor"] , this.params.divLineColor));
		this.params.zeroPlaneAlpha = getFN (atts ["zeroplanealpha"] , 75);
		this.params.zeroPlaneShowBorder = toBoolean (getFN (atts ["zeroplaneshowborder"] , 1));
		this.params.zeroPlaneBorderColor = formatColor (getFV (atts ["zeroplanebordercolor"] , this.params.zeroPlaneColor));
		//Tool Tip - Show/Hide, Background Color, Border Color, Separator Character
		this.params.showToolTip = toBoolean (getFN (atts ["showtooltip"] , atts ["showhovercap"] , 1));
		this.params.seriesNameInToolTip = toBoolean (getFN (atts ["seriesnameintooltip"] , 1));
		this.params.toolTipBgColor = formatColor (getFV (atts ["tooltipbgcolor"] , atts ["hovercapbgcolor"] , atts ["hovercapbg"] , this.defColors.getToolTipBgColor3D (this.params.palette)));
		this.params.toolTipBorderColor = formatColor (getFV (atts ["tooltipbordercolor"] , atts ["hovercapbordercolor"] , atts ["hovercapborder"] , this.defColors.getToolTipBorderColor3D (this.params.palette)));
		this.params.toolTipSepChar = getFV (atts ["tooltipsepchar"] , atts ["hovercapsepchar"] , ", ");
		//Font Properties
		this.params.baseFont = getFV (atts ["basefont"] , "Verdana");
		this.params.baseFontSize = getFN (atts ["basefontsize"] , 10);
		this.params.baseFontColor = formatColor (getFV (atts ["basefontcolor"] , this.defColors.getBaseFontColor3D (this.params.palette)));
		this.params.outCnvBaseFont = getFV (atts ["outcnvbasefont"] , this.params.baseFont);
		this.params.outCnvBaseFontSize = getFN (atts ["outcnvbasefontsize"] , this.params.baseFontSize);
		this.params.outCnvBaseFontColor = formatColor (getFV (atts ["outcnvbasefontcolor"] , this.params.baseFontColor));
		// ------------------------- NUMBER FORMATTING ---------------------------- //
		//Option whether the format the number (using Commas)
		this.params.formatNumber = toBoolean (getFN (atts ["formatnumber"] , 1));
		//Option to format number scale
		this.params.formatNumberScale = toBoolean (getFN (atts ["formatnumberscale"] , 1));
		//Number Scales
		this.params.defaultNumberScale = getFV (atts ["defaultnumberscale"] , "");
		this.params.numberScaleUnit = getFV (atts ["numberscaleunit"] , "K,M");
		this.params.numberScaleValue = getFV (atts ["numberscalevalue"] , "1000,1000");
		//Number prefix and suffix
		this.params.numberPrefix = getFV (atts ["numberprefix"] , "");
		this.params.numberSuffix = getFV (atts ["numbersuffix"] , "");
		//Decimal Separator Character
		this.params.decimalSeparator = getFV (atts ["decimalseparator"] , ".");
		//Thousand Separator Character
		this.params.thousandSeparator = getFV (atts ["thousandseparator"] , ",");
		//Input decimal separator and thousand separator. In some european countries,
		//commas are used as decimal separators and dots as thousand separators. In XML,
		//if the user specifies such values, it will give a error while converting to
		//number. So, we accept the input decimal and thousand separator from user, so that
		//we can covert it accordingly into the required format.
		this.params.inDecimalSeparator = getFV (atts ["indecimalseparator"] , "");
		this.params.inThousandSeparator = getFV (atts ["inthousandseparator"] , "");
		//Decimal Precision (number of decimal places to be rounded to)
		this.params.decimals = getFV (atts ["decimals"] , atts ["decimalprecision"]);
		//Force Decimal Padding
		this.params.forceDecimals = toBoolean (getFN (atts ["forcedecimals"] , 0));
		//y-Axis values decimals
		this.params.yAxisValueDecimals = getFV (atts ["yaxisvaluedecimals"] , atts ["yaxisvaluesdecimals"] , atts ["divlinedecimalprecision"] , atts ["limitsdecimalprecision"]);
		// ---------------- SECONDARY AXIS NUMBER FORMATTING --------------------- //
		this.params.sFormatNumber = toBoolean (getFN (atts ["sformatnumber"] , (this.params.formatNumber) ?1 : 0));
		this.params.sFormatNumberScale = toBoolean (getFN (atts ["sformatnumberscale"] , 0));
		this.params.sDefaultNumberScale = getFV (atts ["sdefaultnumberscale"] , this.params.defaultNumberScale);
		this.params.sNumberScaleUnit = getFV (atts ["snumberscaleunit"] , this.params.numberScaleUnit);
		this.params.sNumberScaleValue = getFV (atts ["snumberscalevalue"] , this.params.numberScaleValue);
		this.params.sNumberPrefix = getFV (atts ["snumberprefix"] , "");
		this.params.sNumberSuffix = getFV (atts ["snumbersuffix"] , "");
		this.params.sDecimals = getFV (atts ["sdecimals"] , this.params.decimals);
		this.params.sForceDecimals = toBoolean (getFN (atts ["sforcedecimals"] , (this.params.forceDecimals) ?1 : 0));
		this.params.sYAxisValueDecimals = getFN (atts ["syaxisvaluedecimals"] , this.params.sDecimals);
	}
	/**
	* getSumOfValues method returns the sum of values of a particular data
	* index in all the data sets. It is used to get the positive and negative
	* sum for the given index.
	*	@param	index	Index for which we've to calculate sum
	*	@return		An object containing PSum and NSum as positive
	*					and negative sum respectively.
	*/
	private function getSumOfValues (index : Number) : Object
	{
		//Loop variables
		var i : Number;
		//Variable to store positive and negative sum
		var pSum : Number, nSum : Number;
		//Return Object
		var rtnObj : Object = new Object ();
		//Iterate through all the datasets for this index
		for (i = 1; i <= this.numDS; i ++)
		{
			//Check only if the data is defined and primary
			if (this.dataset [i].parentYAxis == "P" && this.dataset [i].data [index].isDefined)
			{
				if (this.dataset [i].data [index].value >= 0)
				{
					pSum = (pSum == undefined) ? (this.dataset [i].data [index].value) : (pSum + this.dataset [i].data [index].value);
				}else
				{
					nSum = (nSum == undefined) ? (this.dataset [i].data [index].value) : (nSum + this.dataset [i].data [index].value);
				}
			}
		}
		if (this.sumStored == false)
		{
			//Store the sum of this index in array
			this.sums [index] = new Object ();
			this.sums [index].sum = ((pSum == undefined) ?0 : pSum) + ((nSum == undefined) ?0 : nSum);
			this.sums [index].pSum = pSum;
			this.sums [index].nSum = nSum;
			//Update flag
			if (index == this.num)
			{
				this.sumStored = true;
			}
		}
		//Store values in return object and return
		rtnObj.pSum = pSum;
		rtnObj.nSum = nSum;
		return rtnObj;
	}
	/**
	* getMaxDataValue method gets the maximum y-axis data sum present
	* in the data.
	*	@return	The maximum value present in the data provided.
	*/
	private function getMaxDataValue () : Number 
	{
		var maxValue : Number;
		var firstSumFound : Boolean = false;
		var i : Number;
		var pSum : Number, sNum : Number;
		var sumObj : Object;
		var vitalSum : Number;
		for (i = 1; i <= this.num; i ++)
		{
			sumObj = this.getSumOfValues (i);
			vitalSum = (this.positivePresent == false) ? (sumObj.nSum) : (sumObj.pSum);
			//By default assume the first non-null sum to be maximum
			if (firstSumFound == false)
			{
				if (vitalSum != undefined)
				{
					//Set the flag that "We've found first non-null sum".
					firstSumFound = true;
					//Also assume this value to be maximum.
					maxValue = vitalSum;
				}
			} else 
			{
				//If the first sum has been found and the current sum is defined, compare
				if (vitalSum != undefined)
				{
					//Store the greater number
					maxValue = (vitalSum > maxValue) ? vitalSum : maxValue;
				}
			}
		}
		return maxValue;
	}
	/**
	* getMinDataValue method gets the minimum y-axis data sum present
	* in the data
	*	@reurns		The minimum value present in data
	*/
	private function getMinDataValue () : Number 
	{
		var minValue : Number;
		var firstSumFound : Boolean = false;
		var i : Number;
		var pSum : Number, sNum : Number;
		var sumObj : Object;
		var vitalSum : Number;
		for (i = 1; i <= this.num; i ++)
		{
			sumObj = this.getSumOfValues (i);
			vitalSum = (this.negativePresent == true) ? (sumObj.nSum) : (sumObj.pSum);
			//By default assume the first non-null sum to be minimum
			if (firstSumFound == false)
			{
				if (vitalSum != undefined)
				{
					//Set the flag that "We've found first non-null sum".
					firstSumFound = true;
					//Also assume this value to be minimum.
					minValue = vitalSum;
				}
			} else 
			{
				//If the first sum has been found and the current sum is defined, compare
				if (vitalSum != undefined)
				{
					//Store the lesser number
					minValue = (vitalSum < minValue) ? vitalSum : minValue;
				}
			}
		}
		return minValue;
	}
	/**
	* getMaxSDataValue method gets the maximum y-axis data value present
	* in the Secondary axis data.
	*	@return	The maximum value present in the data provided.
	*/
	private function getMaxSDataValue () : Number 
	{
		var maxValue : Number;
		var firstNumberFound : Boolean = false;
		var i : Number, j : Number;
		for (i = 1; i <= this.numDS; i ++)
		{
			if (this.dataset [i].parentYAxis == "S")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//By default assume the first non-null number to be maximum
					if (firstNumberFound == false)
					{
						if (this.dataset [i].data [j].isDefined == true)
						{
							//Set the flag that "We've found first non-null number".
							firstNumberFound = true;
							//Also assume this value to be maximum.
							maxValue = this.dataset [i].data [j].value;
						}
					} else 
					{
						//If the first number has been found and the current data is defined, compare
						if (this.dataset [i].data [j].isDefined)
						{
							//Store the greater number
							maxValue = (this.dataset [i].data [j].value > maxValue) ? this.dataset [i].data [j].value : maxValue;
						}
					}
				}
			}
		}
		return maxValue;
	}
	/**
	* getMinDataValue method gets the minimum y-axis data value present
	* in the secondary data axis
	*	@reurns		The minimum value present in data
	*/
	private function getMinSDataValue () : Number 
	{
		var minValue : Number;
		var firstNumberFound : Boolean = false;
		var i : Number, j : Number;
		for (i = 1; i <= this.numDS; i ++)
		{
			if (this.dataset [i].parentYAxis == "S")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//By default assume the first non-null number to be minimum
					if (firstNumberFound == false)
					{
						if (this.dataset [i].data [j].isDefined == true)
						{
							//Set the flag that "We've found first non-null number".
							firstNumberFound = true;
							//Also assume this value to be minimum.
							minValue = this.dataset [i].data [j].value;
						}
					} else 
					{
						//If the first number has been found and the current data is defined, compare
						if (this.dataset [i].data [j].isDefined)
						{
							//Store the lesser number
							minValue = (this.dataset [i].data [j].value < minValue) ? this.dataset [i].data [j].value : minValue;
						}
					}
				}
			}
		}
		return minValue;
	}
	/**
	* calculateAxisLimits method sets the axis limits for the chart.
	* It gets the minimum and maximum value specified in data and
	* based on that it calls super.getAxisLimits();
	*/
	private function calculateAxisLimits () : Void 
	{
		this.getPAxisLimits (this.getMaxDataValue () , this.getMinDataValue () , true);
		this.getSAxisLimits (this.getMaxSDataValue () , this.getMinSDataValue () , ! this.params.setAdaptiveSYMin);
	}
	/**
	* setStyleDefaults method sets the default values for styles or
	* extracts information from the attributes and stores them into
	* style objects.
	*/
	private function setStyleDefaults () : Void 
	{
		//Default font object for Caption
		//-----------------------------------------------------------------//
		var captionFont = new StyleObject ();
		captionFont.name = "_SdCaptionFont";
		captionFont.align = "center";
		captionFont.valign = "top";
		captionFont.bold = "1";
		captionFont.font = this.params.outCnvBaseFont;
		captionFont.size = this.params.outCnvBaseFontSize;
		captionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.CAPTION, captionFont, this.styleM.TYPE.FONT, null);
		delete captionFont;
		//-----------------------------------------------------------------//
		//Default font object for SubCaption
		//-----------------------------------------------------------------//
		var subCaptionFont = new StyleObject ();
		subCaptionFont.name = "_SdSubCaptionFont";
		subCaptionFont.align = "center";
		subCaptionFont.valign = "top";
		subCaptionFont.bold = "1";
		subCaptionFont.font = this.params.outCnvBaseFont;
		subCaptionFont.size = this.params.outCnvBaseFontSize;
		subCaptionFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.SUBCAPTION, subCaptionFont, this.styleM.TYPE.FONT, null);
		delete subCaptionFont;
		//-----------------------------------------------------------------//
		//Default font object for YAxisName
		//-----------------------------------------------------------------//
		var yAxisNameFont = new StyleObject ();
		yAxisNameFont.name = "_SdYAxisNameFont";
		yAxisNameFont.align = "center";
		yAxisNameFont.valign = "middle";
		yAxisNameFont.bold = "1";
		yAxisNameFont.font = this.params.outCnvBaseFont;
		yAxisNameFont.size = this.params.outCnvBaseFontSize;
		yAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.YAXISNAME, yAxisNameFont, this.styleM.TYPE.FONT, null);
		delete yAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for XAxisName
		//-----------------------------------------------------------------//
		var xAxisNameFont = new StyleObject ();
		xAxisNameFont.name = "_SdXAxisNameFont";
		xAxisNameFont.align = "center";
		xAxisNameFont.valign = "middle";
		xAxisNameFont.bold = "1";
		xAxisNameFont.font = this.params.outCnvBaseFont;
		xAxisNameFont.size = this.params.outCnvBaseFontSize;
		xAxisNameFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.XAXISNAME, xAxisNameFont, this.styleM.TYPE.FONT, null);
		delete xAxisNameFont;
		//-----------------------------------------------------------------//
		//Default font object for trend lines
		//-----------------------------------------------------------------//
		var trendFont = new StyleObject ();
		trendFont.name = "_SdTrendFont";
		trendFont.font = this.params.outCnvBaseFont;
		trendFont.size = this.params.outCnvBaseFontSize;
		trendFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.TRENDVALUES, trendFont, this.styleM.TYPE.FONT, null);
		delete trendFont;
		//-----------------------------------------------------------------//
		//Default font object for yAxisValues
		//-----------------------------------------------------------------//
		var yAxisValuesFont = new StyleObject ();
		yAxisValuesFont.name = "_SdYAxisValuesFont";
		yAxisValuesFont.align = "right";
		yAxisValuesFont.valign = "middle";
		yAxisValuesFont.font = this.params.outCnvBaseFont;
		yAxisValuesFont.size = this.params.outCnvBaseFontSize;
		yAxisValuesFont.color = this.params.outCnvBaseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.YAXISVALUES, yAxisValuesFont, this.styleM.TYPE.FONT, null);
		delete yAxisValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for DataLabels
		//-----------------------------------------------------------------//
		var dataLabelsFont = new StyleObject ();
		dataLabelsFont.name = "_SdDataLabelsFont";
		dataLabelsFont.align = "center";
		dataLabelsFont.valign = "bottom";
		dataLabelsFont.font = this.params.catFont;
		dataLabelsFont.size = this.params.catFontSize;
		dataLabelsFont.color = this.params.catFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.DATALABELS, dataLabelsFont, this.styleM.TYPE.FONT, null);
		delete dataLabelsFont;
		//-----------------------------------------------------------------//
		//Default font object for Legend
		//-----------------------------------------------------------------//
		var legendFont = new StyleObject ();
		legendFont.name = "_SdLegendFont";
		legendFont.font = this.params.outCnvBaseFont;
		legendFont.size = this.params.outCnvBaseFontSize;
		legendFont.color = this.params.outCnvBaseFontColor;
		legendFont.ishtml = 1;
		legendFont.leftmargin = 3;
		//Over-ride
		this.styleM.overrideStyle (this.objects.LEGEND, legendFont, this.styleM.TYPE.FONT, null);
		delete legendFont;
		//-----------------------------------------------------------------//
		//Default font object for DataValues
		//-----------------------------------------------------------------//
		var dataValuesFont = new StyleObject ();
		dataValuesFont.name = "_SdDataValuesFont";
		dataValuesFont.align = "center";
		dataValuesFont.valign = "middle";
		dataValuesFont.font = this.params.baseFont;
		dataValuesFont.size = this.params.baseFontSize;
		dataValuesFont.color = this.params.baseFontColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.DATAVALUES, dataValuesFont, this.styleM.TYPE.FONT, null);
		delete dataValuesFont;
		//-----------------------------------------------------------------//
		//Default font object for ToolTip
		//-----------------------------------------------------------------//
		var toolTipFont = new StyleObject ();
		toolTipFont.name = "_SdToolTipFont";
		toolTipFont.font = this.params.baseFont;
		toolTipFont.size = this.params.baseFontSize;
		toolTipFont.color = this.params.baseFontColor;
		toolTipFont.bgcolor = this.params.toolTipBgColor;
		toolTipFont.bordercolor = this.params.toolTipBorderColor;
		//Over-ride
		this.styleM.overrideStyle (this.objects.TOOLTIP, toolTipFont, this.styleM.TYPE.FONT, null);
		delete toolTipFont;
		//-----------------------------------------------------------------//
		//Default Effect (Shadow) object for DataPlot
		//-----------------------------------------------------------------//
		if (this.params.showShadow)
		{
			var dataPlotShadow = new StyleObject ();
			dataPlotShadow.name = "_SdDataPlotShadow";
			dataPlotShadow.distance = 3;
			dataPlotShadow.angle = 315;
			dataPlotShadow.alpha = 75;
			dataPlotShadow.color = "666666";
			dataPlotShadow.blurx = 8;
			dataPlotShadow.blury = 8;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOTCOLUMN, dataPlotShadow, this.styleM.TYPE.SHADOW, null);
			this.styleM.overrideStyle (this.objects.DATAPLOTLINE, dataPlotShadow, this.styleM.TYPE.SHADOW, null);
			delete dataPlotShadow;
		}
		//-----------------------------------------------------------------//
		//Default Effect (Shadow) object for Legend
		//-----------------------------------------------------------------//
		if (this.params.legendShadow)
		{
			var legendShadow = new StyleObject ();
			legendShadow.name = "_SdLegendShadow";
			legendShadow.distance = 2;
			legendShadow.alpha = 90;
			legendShadow.angle = 45;
			//Over-ride
			this.styleM.overrideStyle (this.objects.LEGEND, legendShadow, this.styleM.TYPE.SHADOW, null);
			delete legendShadow;
		}
		//-----------------------------------------------------------------//
		//Default Animation object for DataPlot (if required)
		//-----------------------------------------------------------------//
		if (this.params.defaultAnimation)
		{
			var dataPlotAnim = new StyleObject ();
			dataPlotAnim.name = "_SdDataPlotAnim";
			dataPlotAnim.param = "_yscale";
			dataPlotAnim.easing = "regular";
			dataPlotAnim.wait = 0;
			dataPlotAnim.start = 0;
			dataPlotAnim.duration = 1;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOTCOLUMN, dataPlotAnim, this.styleM.TYPE.ANIMATION, "_yscale");
			delete dataPlotAnim;
			// Alpha effect for anchors - Line
			var anchorsAnim = new StyleObject ();
			anchorsAnim.name = "_SdDataAnchorAnim";
			anchorsAnim.param = "_alpha";
			anchorsAnim.easing = "regular";
			anchorsAnim.wait = 0;
			anchorsAnim.start = 0;
			anchorsAnim.duration = 0.5;
			//Over-ride
			this.styleM.overrideStyle (this.objects.ANCHORS, anchorsAnim, this.styleM.TYPE.ANIMATION, "_alpha");
			delete anchorsAnim;
			//For Line - 2 animation effects - xScale and subsequent yScale
			var dataPlotAnimLineX = new StyleObject ();
			dataPlotAnimLineX.name = "_SdDataPlotLineAnimXScale";
			dataPlotAnimLineX.param = "_xscale";
			dataPlotAnimLineX.easing = "regular";
			dataPlotAnimLineX.wait = 0;
			dataPlotAnimLineX.start = 0;
			dataPlotAnimLineX.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOTLINE, dataPlotAnimLineX, this.styleM.TYPE.ANIMATION, "_xscale");
			delete dataPlotAnimLineX;
			//YScale for line
			var dataPlotAnimLineY = new StyleObject ();
			dataPlotAnimLineY.name = "_SdDataPlotLineAnimYScale";
			dataPlotAnimLineY.param = "_yscale";
			dataPlotAnimLineY.easing = "regular";
			dataPlotAnimLineY.wait = 0.7;
			dataPlotAnimLineY.start = 0.1;
			dataPlotAnimLineY.duration = 0.7;
			//Over-ride
			this.styleM.overrideStyle (this.objects.DATAPLOTLINE, dataPlotAnimLineY, this.styleM.TYPE.ANIMATION, "_yscale");
			delete dataPlotAnimLineY;
		}
		//-----------------------------------------------------------------//
		
	}
	/**
	* calcVLinesPos method calculates the x position for the various
	* vLines defined. Also, it validates them.
	*/
	private function calcVLinesPos ()
	{
		var i : Number;
		//Iterate through all the vLines
		for (i = 1; i <= numVLines; i ++)
		{
			//If the vLine is after 1st data and before last data
			if (this.vLines [i].index > 0 && this.vLines [i].index < this.num)
			{
				//Set it's x position
				this.vLines [i].x = this.categories [this.vLines [i].index].x + (this.categories [this.vLines [i].index + 1].x - this.categories [this.vLines [i].index].x) / 2;
			} else 
			{
				//Invalidate it
				this.vLines [i].isValid = false;
			}
		}
	}
	/**
	* calculatePoints method calculates the various points on the chart.
	*/
	private function calculatePoints ()
	{
		//Loop variable
		var i : Number;
		var j : Number;
		//Feed empty data - By default there should be equal number of <categories>
		//and <set> element within each dataset. If in case, <set> elements fall short,
		//we need to append empty data at the end.
		for (i = 1; i <= this.numDS; i ++)
		{
			for (j = 1; j <= this.num; j ++)
			{
				if (this.dataset [i].data [j] == undefined)
				{
					this.dataset [i].data [j] = this.returnDataAsObject (NaN);
				}
			}
		}
		//Format all the numbers on the chart and store their display values
		//We format and store here itself, so that later, whenever needed,
		//we just access displayValue instead of formatting once again.
		//Also set tool tip text values
		var toolText : String
		var sumFormatted : Boolean;
		for (i = 1; i <= this.numDS; i ++)
		{
			for (j = 1; j <= this.num; j ++)
			{
				if (this.dataset [i].parentYAxis == "P")
				{
					//Format and store
					this.dataset [i].data [j].displayValue = formatNumber (this.dataset [i].data [j].value, this.params.formatNumber, this.params.decimals, this.params.forceDecimals, this.params.formatNumberScale, this.params.defaultNumberScale, this.config.nsv, this.config.nsu, this.params.numberPrefix, this.params.numberSuffix);
					//Format sum of values
					if (this.params.showSum && ! (sumFormatted))
					{
						this.sums [j].displayValue = formatNumber (this.sums [j].sum, this.params.formatNumber, this.params.decimals, this.params.forceDecimals, this.params.formatNumberScale, this.params.defaultNumberScale, this.config.nsv, this.config.nsu, this.params.numberPrefix, this.params.numberSuffix);
					}
				}else
				{
					this.dataset [i].data [j].displayValue = formatNumber (this.dataset [i].data [j].value, this.params.sFormatNumber, this.params.sDecimals, this.params.sForceDecimals, this.params.sFormatNumberScale, this.params.sDefaultNumberScale, this.config.snsv, this.config.snsu, this.params.sNumberPrefix, this.params.sNumberSuffix);
				}
				//Tool tip text.
				//Preferential Order - Set Tool Text (No concatenation) > SeriesName + Cat Name + Value
				if (this.dataset [i].data [j].toolText == undefined || this.dataset [i].data [j].toolText == "")
				{
					//If the tool tip text is not already defined
					//If labels have been defined
					toolText = (this.params.seriesNameInToolTip && this.dataset [i].seriesName != "") ? (this.dataset [i].seriesName + this.params.toolTipSepChar) : "";
					toolText = toolText + ((this.categories [j].toolText != "") ? (this.categories [j].toolText + this.params.toolTipSepChar) : "");
					toolText = toolText + this.dataset [i].data [j].displayValue;
					this.dataset [i].data [j].toolText = toolText;
				}
			}
			if (this.dataset [i].parentYAxis == "P")
			{
				sumFormatted = true;
			}
		}
		//Based on label step, set showLabel of each data point as required.
		//Visible label count
		var visibleCount : Number = 0;
		var finalVisibleCount : Number = 0;
		for (i = 1; i <= this.num; i ++)
		{
			//Now, the label can be preset to be hidden (set via XML)
			if (this.categories [i].showLabel)
			{
				visibleCount ++;
				//If label step is defined, we need to set showLabel of those
				//labels which fall on step as false.
				if ((i - 1) % this.params.labelStep == 0)
				{
					this.categories [i].showLabel = true;
				} else 
				{
					this.categories [i].showLabel = false;
				}
			}
			//Update counter
			finalVisibleCount = (this.categories [i].showLabel) ? (finalVisibleCount + 1) : (finalVisibleCount);
		}
		//We now need to calculate the available Width on the canvas.
		//Available width = total Chart width minus the list below
		// - Left and Right Margin
		// - PYAxisName (if to be shown)
		// - yAxisValues
		// - Trend line display values (both left side and right side).
		// - SYAxisName
		var canvasWidth : Number = this.width - (this.params.chartLeftMargin + this.params.chartRightMargin);
		//Set canvas startX
		var canvasStartX : Number = this.params.chartLeftMargin;
		//Now, if y-axis name is to be shown, simulate it and get the width
		if (this.params.PYAxisName != "")
		{
			//Get style object
			var yAxisNameStyle : Object = this.styleM.getTextStyle (this.objects.YAXISNAME);
			if (this.params.rotateYAxisName)
			{
				//Set embedded font - as we need to rotate
				yAxisNameStyle.font = _embeddedFont;
				//Un-bold and un-italicize
				yAxisNameStyle.bold = false;
				yAxisNameStyle.italic = false;
				//Create text field to get width
				var yAxisNameObj : Object = createText (true, this.params.PYAxisName, this.tfTestMC, 1, testTFX, testTFY, 90, yAxisNameStyle, false, 0, 0);
				//Accomodate width and padding
				canvasStartX = canvasStartX + yAxisNameObj.width + this.params.yAxisNamePadding;
				canvasWidth = canvasWidth - yAxisNameObj.width - this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.yAxisName = returnDataAsElement (0, 0, yAxisNameObj.width, yAxisNameObj.height);
			}else
			{
				//If the y-axis name is not to be rotated
				//Calculate the width of the text if in full horizontal mode
				//Create text field to get width
				var yAxisNameObj : Object = createText (true, this.params.PYAxisName, this.tfTestMC, 1, testTFX, testTFY, 0, yAxisNameStyle, false, 0, 0);
				//Get a value for this.params.PYAxisNameWidth
				this.params.PYAxisNameWidth = Number (getFV (this.params.PYAxisNameWidth, yAxisNameObj.width));
				//Get the lesser of the width (to avoid un-necessary space)
				this.params.PYAxisNameWidth = Math.min (this.params.PYAxisNameWidth, yAxisNameObj.width);
				//Accomodate width and padding
				canvasStartX = canvasStartX + this.params.PYAxisNameWidth + this.params.yAxisNamePadding;
				canvasWidth = canvasWidth - this.params.PYAxisNameWidth - this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.yAxisName = returnDataAsElement (0, 0, this.params.yAxisNameWidth, yAxisNameObj.height);
			}
			delete yAxisNameStyle;
			delete yAxisNameObj;
		}
		//Accomodate width for y-axis values. Now, y-axis values conists of two parts
		//(for backward compatibility) - limits (upper and lower) and div line values.
		//So, we'll have to individually run through both of them.
		var yAxisValMaxWidth : Number = 0;
		var divLineObj : Object;
		var divStyle : Object = this.styleM.getTextStyle (this.objects.YAXISVALUES);
		//Iterate through all the div line values
		for (i = 1; i < this.divLines.length; i ++)
		{
			//If div line value is to be shown
			if (this.divLines [i].showValue)
			{
				//If it's the first or last div Line (limits), and it's to be shown
				if ((i == 1) || (i == this.divLines.length - 1))
				{
					if (this.params.showLimits)
					{
						//Get the width of the text
						divLineObj = createText (true, this.divLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						yAxisValMaxWidth = (divLineObj.width > yAxisValMaxWidth) ? (divLineObj.width) : (yAxisValMaxWidth);
					}
				} else 
				{
					//It's a div interval - div line
					//So, check if we've to show div line values
					if (this.params.showDivLineValues)
					{
						//Get the width of the text
						divLineObj = createText (true, this.divLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						yAxisValMaxWidth = (divLineObj.width > yAxisValMaxWidth) ? (divLineObj.width) : (yAxisValMaxWidth);
					}
				}
			}
		}
		delete divLineObj;
		//Also iterate through all trend lines whose values are to be shown on
		//left side of the canvas.
		//Get style object
		var trendStyle : Object = this.styleM.getTextStyle (this.objects.TRENDVALUES);
		var trendObj : Object;
		for (i = 1; i <= this.numTrendLines; i ++)
		{
			if (this.trendLines [i].isValid == true && this.trendLines [i].valueOnRight == false)
			{
				//If it's a valid trend line and value is to be shown on left
				//Get the width of the text
				trendObj = createText (true, this.trendLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, trendStyle, false, 0, 0);
				//Accomodate
				yAxisValMaxWidth = (trendObj.width > yAxisValMaxWidth) ? (trendObj.width) : (yAxisValMaxWidth);
			}
		}
		//Accomodate for y-axis/left-trend line values text width
		if (yAxisValMaxWidth > 0)
		{
			canvasStartX = canvasStartX + yAxisValMaxWidth + this.params.yAxisValuesPadding;
			canvasWidth = canvasWidth - yAxisValMaxWidth - this.params.yAxisValuesPadding;
		}
		//Accomodate width for secondary y-axis values. Now, y-axis values conists of two parts
		//(for backward compatibility) - limits (upper and lower) and div line values.
		//So, we'll have to individually run through both of them.
		var SYAxisValMaxWidth : Number = 0;
		var divLineObj : Object;
		var divStyle : Object = this.styleM.getTextStyle (this.objects.YAXISVALUES);
		//Iterate through all the div line values
		for (i = 1; i < this.sDivLines.length; i ++)
		{
			//If div line value is to be shown
			if (this.sDivLines [i].showValue)
			{
				//If it's the first or last div Line (limits), and it's to be shown
				if ((i == 1) || (i == this.sDivLines.length - 1))
				{
					if (this.params.showSecondaryLimits)
					{
						//Get the width of the text
						divLineObj = createText (true, this.sDivLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						SYAxisValMaxWidth = (divLineObj.width > SYAxisValMaxWidth) ? (divLineObj.width) : (SYAxisValMaxWidth);
					}
				} else 
				{
					//It's a div interval - div line
					//So, check if we've to show div line values
					if (this.params.showDivLineSecondaryValue)
					{
						//Get the width of the text
						divLineObj = createText (true, this.sDivLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, divStyle, false, 0, 0);
						//Accomodate
						SYAxisValMaxWidth = (divLineObj.width > SYAxisValMaxWidth) ? (divLineObj.width) : (SYAxisValMaxWidth);
					}
				}
			}
		}
		delete divLineObj;
		//Also iterate through all trend lines whose values are to be shown on
		//right side of the canvas.
		//Get style object
		var trendStyle : Object = this.styleM.getTextStyle (this.objects.TRENDVALUES);
		var trendObj : Object;
		for (i = 1; i <= this.numTrendLines; i ++)
		{
			if (this.trendLines [i].isValid == true && this.trendLines [i].valueOnRight == true)
			{
				//If it's a valid trend line and value is to be shown on right
				//Get the width of the text
				trendObj = createText (true, this.trendLines [i].displayValue, this.tfTestMC, 1, testTFX, testTFY, 0, trendStyle, false, 0, 0);
				//Accomodate
				SYAxisValMaxWidth = (trendObj.width > SYAxisValMaxWidth) ? (trendObj.width) : (SYAxisValMaxWidth);
			}
		}
		//Accomodate for secondary y-axis/right-trend line values text width
		if (SYAxisValMaxWidth > 0)
		{
			canvasWidth = canvasWidth - SYAxisValMaxWidth - this.params.yAxisValuesPadding;
		}
		this.config.rightSideValueWidth = SYAxisValMaxWidth;
		//Now, if secondary y-axis name is to be shown, simulate it and get the width
		if (this.params.SYAxisName != "")
		{
			//Get style object
			var yAxisNameStyle : Object = this.styleM.getTextStyle (this.objects.YAXISNAME);
			if (this.params.rotateYAxisName)
			{
				//Set embedded font - as we need to rotate
				yAxisNameStyle.font = _embeddedFont;
				//Un-bold and un-italicize
				yAxisNameStyle.bold = false;
				yAxisNameStyle.italic = false;
				//Create text field to get width
				var yAxisNameObj : Object = createText (true, this.params.SYAxisName, this.tfTestMC, 1, testTFX, testTFY, 90, yAxisNameStyle, false, 0, 0);
				//Accomodate width and padding
				canvasWidth = canvasWidth - yAxisNameObj.width - this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.SYAxisName = returnDataAsElement (0, 0, yAxisNameObj.width, yAxisNameObj.height);
			}else
			{
				//If the y-axis name is not to be rotated
				//Calculate the width of the text if in full horizontal mode
				//Create text field to get width
				var yAxisNameObj : Object = createText (true, this.params.SYAxisName, this.tfTestMC, 1, testTFX, testTFY, 0, yAxisNameStyle, false, 0, 0);
				//Get a value for this.params.PYAxisNameWidth
				this.params.SYAxisNameWidth = Number (getFV (this.params.SYAxisNameWidth, yAxisNameObj.width));
				//Get the lesser of the width (to avoid un-necessary space)
				this.params.SYAxisNameWidth = Math.min (this.params.SYAxisNameWidth, yAxisNameObj.width);
				//Accomodate width and padding
				canvasWidth = canvasWidth - this.params.SYAxisNameWidth - this.params.yAxisNamePadding;
				//Create element for yAxisName - to store width/height
				this.elements.SYAxisName = returnDataAsElement (0, 0, this.params.SYAxisNameWidth, yAxisNameObj.height);
			}
			delete yAxisNameStyle;
			delete yAxisNameObj;
		}
		//Round them off finally to avoid distorted pixels
		canvasStartX = int (canvasStartX);
		canvasWidth = int (canvasWidth);
		//We finally have canvas Width and canvas Start X
		//-----------------------------------------------------------------------------------//
		//Now, we need to calculate the available Height on the canvas.
		//Available height = total Chart height minus the list below
		// - Chart Top and Bottom Margins
		// - Space for Caption, Sub Caption and caption padding
		// - Height of data labels
		// - xAxisName
		//Initialize canvasHeight to total height minus margins
		var canvasHeight : Number = this.height - (this.params.chartTopMargin + this.params.chartBottomMargin);
		//Set canvasStartY
		var canvasStartY : Number = this.params.chartTopMargin;
		//Now, if we've to show caption
		if (this.params.caption != "")
		{
			//Create text field to get height
			var captionObj : Object = createText (true, this.params.caption, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle (this.objects.CAPTION) , false, 0, 0);
			//Store the height
			canvasStartY = canvasStartY + captionObj.height;
			canvasHeight = canvasHeight - captionObj.height;
			//Create element for caption - to store width & height
			this.elements.caption = returnDataAsElement (0, 0, captionObj.width, captionObj.height);
			delete captionObj;
		}
		//Now, if we've to show sub-caption
		if (this.params.subCaption != "")
		{
			//Create text field to get height
			var subCaptionObj : Object = createText (true, this.params.subCaption, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle (this.objects.SUBCAPTION) , false, 0, 0);
			//Store the height
			canvasStartY = canvasStartY + subCaptionObj.height;
			canvasHeight = canvasHeight - subCaptionObj.height;
			//Create element for sub caption - to store height
			this.elements.subCaption = returnDataAsElement (0, 0, subCaptionObj.width, subCaptionObj.height);
			delete subCaptionObj;
		}
		//Now, if either caption or sub-caption was shown, we also need to adjust caption padding
		if (this.params.caption != "" || this.params.subCaption != "")
		{
			//Account for padding
			canvasStartY = canvasStartY + this.params.captionPadding;
			canvasHeight = canvasHeight - this.params.captionPadding;
		}
		//Now, if data labels are to be shown, we need to account for their heights
		//Data labels can be rendered in 3 ways:
		//1. Normal - no staggering - no wrapping - no rotation
		//2. Wrapped - no staggering - no rotation
		//3. Staggered - no wrapping - no rotation
		//4. Rotated - no staggering - no wrapping
		//Placeholder to store max height
		this.config.maxLabelHeight = 0;
		this.config.labelAreaHeight = 0;
		var labelObj : Object;
		var labelStyleObj : Object = this.styleM.getTextStyle (this.objects.DATALABELS);
		if (this.params.labelDisplay == "ROTATE")
		{
			//Case 4: If the labels are rotated, we iterate through all the string labels
			//provided to us and get the height and store max.
			for (i = 1; i <= this.num; i ++)
			{
				//If the label is to be shown
				if (this.categories [i].showLabel)
				{
					//Set style bold/italic to false and font to embedded font
					labelStyleObj.font = _embeddedFont;
					labelStyleObj.bold = false;
					labelStyleObj.italic = false;
					//Create text box and get height
					labelObj = createText (true, this.categories [i].label, this.tfTestMC, 1, testTFX, testTFY, this.config.labelAngle, labelStyleObj, false, 0, 0);
					//Store the larger
					this.config.maxLabelHeight = (labelObj.height > this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
				}
			}
			//Store max label height as label area height.
			this.config.labelAreaHeight = this.config.maxLabelHeight;
		} else if (this.params.labelDisplay == "WRAP")
		{
			//Case 2 (WRAP): Create all the labels on the chart. Set width as
			//totalAvailableWidth/finalVisibleCount.
			//Set max height as 50% of available canvas height at this point of time. Find all
			//and select the max one.
			var maxLabelWidth : Number = ((canvasWidth - (2 * this.params.canvasPadding)) / finalVisibleCount);
			var maxLabelHeight : Number = (canvasHeight / 2);
			//Store it in config for later usage
			this.config.wrapLabelWidth = maxLabelWidth;
			this.config.wrapLabelHeight = maxLabelHeight;
			for (i = 1; i <= this.num; i ++)
			{
				//If the label is to be shown
				if (this.categories [i].showLabel)
				{
					//Create text box and get height
					labelObj = createText (true, this.categories [i].label, this.tfTestMC, 1, testTFX, testTFY, 0, labelStyleObj, true, maxLabelWidth, maxLabelHeight);
					//Store the larger
					this.config.maxLabelHeight = (labelObj.height > this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
				}
			}
			//Store max label height as label area height.
			this.config.labelAreaHeight = this.config.maxLabelHeight;
		} else 
		{
			//Case 1,3: Normal or Staggered Label
			//We iterate through all the labels, and if any of them has &lt or < (HTML marker)
			//embedded in them, we add them to the array, as for them, we'll need to individually
			//create and see the text height. Also, the first element in the array - we set as
			//ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_=....
			//Create array to store labels.
			var strLabels : Array = new Array ();
			strLabels.push ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_=/*-+~`");
			//Now, iterate through all the labels and for those visible labels, whcih have < sign,
			//add it to array.
			for (i = 1; i <= this.num; i ++)
			{
				//If the label is to be shown
				if (this.categories [i].showLabel)
				{
					if ((this.categories [i].label.indexOf ("&lt;") > - 1) || (this.categories [i].label.indexOf ("<") > - 1))
					{
						strLabels.push (this.categories [i].label);
					}
				}
			}
			//Now, we've the array for which we've to check height (for each element).
			for (i = 0; i < strLabels.length; i ++)
			{
				//Create text box and get height
				labelObj = createText (true, this.categories [i].label, this.tfTestMC, 1, testTFX, testTFY, 0, labelStyleObj, false, 0, 0);
				//Store the larger
				this.config.maxLabelHeight = (labelObj.height > this.config.maxLabelHeight) ? (labelObj.height) : (this.config.maxLabelHeight);
			}
			//We now have the max label height. If it's staggered, then store accordingly, else
			//simple mode
			if (this.params.labelDisplay == "STAGGER")
			{
				//Multiply max label height by stagger lines.
				this.config.labelAreaHeight = this.params.staggerLines * this.config.maxLabelHeight;
			} else 
			{
				this.config.labelAreaHeight = this.config.maxLabelHeight;
			}
		}
		if (this.config.labelAreaHeight > 0)
		{
			//Deduct the calculated label height from canvas height
			canvasHeight = canvasHeight - this.config.labelAreaHeight - this.params.labelPadding;
		}
		//Delete objects
		delete labelObj;
		delete labelStyleObj;
		//Accomodate space for xAxisName (if to be shown);
		if (this.params.xAxisName != "")
		{
			//Create text field to get height
			var xAxisNameObj : Object = createText (true, this.params.xAxisName, this.tfTestMC, 1, testTFX, testTFY, 0, this.styleM.getTextStyle (this.objects.XAXISNAME) , false, 0, 0);
			//Store the height
			canvasHeight = canvasHeight - xAxisNameObj.height - this.params.xAxisNamePadding;
			//Object to store width and height of xAxisName
			this.elements.xAxisName = returnDataAsElement (0, 0, xAxisNameObj.width, xAxisNameObj.height);
			delete xAxisNameObj;
		}
		//We now finally have canvas start Y and canvas height
		//We now check whether the legend is to be drawn
		if (this.params.showLegend)
		{
			//Object to store dimensions
			var lgndDim : Object = lgnd.getDimensions ();
			//Create container movie clip for legend
			this.lgndMC = this.cMC.createEmptyMovieClip ("Legend", this.dm.getDepth ("LEGEND"));
			//Create instance of legend
			if (this.params.legendPosition == "BOTTOM")
			{
				//Maximum Height - 50% of stage
				lgnd = new Legend (lgndMC, this.styleM.getTextStyle (this.objects.LEGEND) , this.params.legendPosition, canvasStartX + canvasWidth / 2, this.height / 2, canvasWidth, (this.height - (this.params.chartTopMargin + this.params.chartBottomMargin)) * 0.5, this.params.legendAllowDrag, this.width, this.height, this.params.legendBgColor, this.params.legendBgAlpha, this.params.legendBorderColor, this.params.legendBorderThickness, this.params.legendBorderAlpha, this.params.legendScrollBgColor, this.params.legendScrollBarColor, this.params.legendScrollBtnColor);
			} 
			else 
			{
				//Maximum Width - 40% of stage
				lgnd = new Legend (lgndMC, this.styleM.getTextStyle (this.objects.LEGEND) , this.params.legendPosition, this.width / 2, canvasStartY + canvasHeight / 2, (this.width - (this.params.chartLeftMargin + this.params.chartRightMargin)) * 0.4, canvasHeight, this.params.legendAllowDrag, this.width, this.height, this.params.legendBgColor, this.params.legendBgAlpha, this.params.legendBorderColor, this.params.legendBorderThickness, this.params.legendBorderAlpha, this.params.legendScrollBgColor, this.params.legendScrollBarColor, this.params.legendScrollBtnColor);
			}
			//Feed data set series Name for legend
			for (i = 1; i <= this.numDS; i ++)
			{
				if (this.dataset [i].includeInLegend && this.dataset [i].seriesName != "")
				{
					lgnd.addItem (this.dataset [i].seriesName, this.dataset [i].color);
				}
			}
			if (this.params.legendPosition == "BOTTOM")
			{
				lgndDim = lgnd.getDimensions ();
				//Now deduct the height from the calculated canvas height
				canvasHeight = canvasHeight - lgndDim.height - this.params.legendPadding;
				//Re-set the legend position
				this.lgnd.resetXY (canvasStartX + canvasWidth / 2, this.height - this.params.chartBottomMargin - lgndDim.height / 2);
			}
			else
			{
				//Get dimensions
				lgndDim = lgnd.getDimensions ();
				//Now deduct the width from the calculated canvas width
				canvasWidth = canvasWidth - lgndDim.width - this.params.legendPadding;
				//Right position
				this.lgnd.resetXY (this.width - this.params.chartRightMargin - lgndDim.width / 2, canvasStartY + canvasHeight / 2);
			}
		}
		//Create an element to represent the canvas now.
		this.elements.canvas = returnDataAsElement (canvasStartX, canvasStartY, canvasWidth, canvasHeight);
		//Now, we have the size for the entire chart canvas
		//The canvas comprises of two things - canvas background and canvas base
		//The height and slant width of canvas base depends on the number of columns and width (depth) of each column
		//Now, we will calculate the space to be alloted to the canvasBg and canvasBase
		//First, depending on the number of columns, calculate the width of each column.
		var colWidth : Number = ((this.elements.canvas.w - this.params.canvasBgDepth - 2 * this.params.canvasPadding) * ((100 - this.params.plotSpacePercent) / 100)) / (this.num);
		//Set the flag for overlapColumns based on column width
		//We overlap columns only if the column width < this.params.maxColWidth
		var overlapColumns : Number = (colWidth < this.params.maxColWidth) ?1 : 0;
		this.params.overlapColumns = toBoolean (getFN (this.params.overlapColumns, overlapColumns));
		//If overlap is false or num Columns==1, we check against max width of columns
		if ( ! this.params.overlapColumns || this.num == 1)
		{
			colWidth = (colWidth > this.params.maxColWidth) ? this.params.maxColWidth : colWidth;
		}
		//Calculate and store the shifts
		this.config.shifts = Column3D.calcShifts (colWidth, 45, - 1);
		//Now, if we've to overlap columns (with number of columns >1)
		//we need to re-calculate column width
		if (this.params.overlapColumns && this.num > 1)
		{
			//Set spacing to 0 - as columns would now overlap each other
			this.params.plotSpacePercent = 0;
			//Get the maximum possible x-space that the shadow of all columns can take.
			var totalShadow : Number = (this.config.shifts.wShadow) * (this.num);
			//Do a conditional check to alter total shadow space
			if (this.config.shifts.wShadow >= this.config.shifts.wFront)
			{
				//If the columns are high depth columns.
				totalShadow = totalShadow * (this.config.shifts.wFront / this.config.shifts.wShadow);
			} else 
			{
				//Low depth columns - more width on front side.
				totalShadow = totalShadow * 0.5;
			}
			//Get new column width based on the above calculated figures
			colWidth = ((this.elements.canvas.w - this.params.canvasBgDepth) + (totalShadow * 0.5) - (2 * this.params.canvasPadding)) / (this.num);
			//Re-calculate the column 3D Shifts
			this.config.shifts = Column3D.calcShifts (colWidth, 45, - 1);
		}
		//Now, store canvas base and canvas bg as elements of chart
		this.elements.canvasBg = returnDataAsElement (this.elements.canvas.x, this.elements.canvas.y, this.elements.canvas.w - this.params.canvasBgDepth, this.elements.canvas.h - this.params.canvasBaseDepth - this.config.shifts.yShift);
		this.elements.canvasBase = returnDataAsElement (this.elements.canvas.x, this.elements.canvasBg.toY, this.elements.canvasBg.w, this.config.shifts.yShift);
		//Calculate space between two columns
		if (this.num > 2)
		{
			//Equally distribute them on the canvas.
			var colSpace : Number = ((this.elements.canvasBg.w - 2 * this.params.canvasPadding) - (colWidth * this.num)) / (this.num - 1);
		} else 
		{
			//If it's only 1 or 2 columns, we center align them instead of equal distribution.
			var colSpace : Number = ((this.elements.canvasBg.w - 2 * this.params.canvasPadding) - (colWidth * this.num)) / (this.num + 1);
		}
		//We finally have column width and space
		//Store it in config
		this.config.columnWidth = colWidth;
		this.config.columnSpace = colSpace;
		//We now need to calculate the position of columns on the chart.
		//Base Plane position - Base plane is the y-plane from which columns start.
		//If there's a 0 value in between yMin,yMax, base plane represents 0 value.
		//Else, it's yMin
		if (this.config.PYMax >= 0 && this.config.PYMin < 0)
		{
			//Negative number present - so set basePlanePos as 0 value
			this.config.basePlanePos = this.getAxisPosition (0, this.config.PYMax, this.config.PYMin, this.elements.canvasBg.y, this.elements.canvasBg.toY, true, 0);
		} else 
		{
			//No negative numbers - so set basePlanePos as yMin value
			this.config.basePlanePos = this.getAxisPosition (this.config.PYMin, this.config.PYMax, this.config.PYMin, this.elements.canvasBg.y, this.elements.canvasBg.toY, true, 0);
		}
		//Store referential depths for each stacked column
		for (i = 1; i <= this.num; i ++)
		{
			var pDepth : Number = this.numDS + 1;
			//Negative depth goes reverse
			var nDepth : Number = this.numDS;
			for (j = 1; j <= this.numDS; j ++)
			{
				if (this.dataset [j].parentYAxis == "P")
				{
					//If the data is defined
					if (this.dataset [j].data [i].isDefined)
					{
						if (this.dataset [j].data [i].value >= 0)
						{
							this.dataset [j].data [i].depth = pDepth;
							pDepth ++;
						} else 
						{
							this.dataset [j].data [i].depth = nDepth;
							nDepth --;
						}
					}
				}
			}
		}
		var dataEndY : Number;
		//Now, store the positions of the columns
		for (i = 1; i <= this.num; i ++)
		{
			//Position co-ordinates
			var posY : Number = 0;
			var negY : Number = 0;
			//Categories x-Position
			if (this.num > 2)
			{
				this.categories [i].x = this.elements.canvasBg.x + this.params.canvasPadding + (colSpace * (i - 1)) + ((i - 0.5) * colWidth) - this.config.shifts.xShift;
			} else 
			{
				this.categories [i].x = this.elements.canvasBg.x + this.params.canvasPadding + (colSpace * i) + ((i - 0.5) * colWidth) - this.config.shifts.xShift;
			}
			//Iterate through all data sets for each index
			for (j = 1; j <= this.numDS; j ++)
			{
				if (this.dataset [j].parentYAxis == "P")
				{
					if (this.dataset [j].data [i].isDefined)
					{
						//X-Position of the column
						this.dataset [j].data [i].x = this.categories [i].x;
						//Height for each column
						dataEndY = this.getAxisPosition (this.dataset [j].data [i].value, this.config.PYMax, this.config.PYMin, this.elements.canvasBg.y, this.elements.canvasBg.toY, true, 0);
						//Negate to cancel Flash's reverse Y Co-ordinate system
						this.dataset [j].data [i].h = - (dataEndY - this.config.basePlanePos);
						//Set the y position
						this.dataset [j].data [i].y = ((this.dataset [j].data [i].h >= 0) ?posY : negY) + this.config.basePlanePos + this.config.shifts.yShift;
						//Store value textbox y position
						this.dataset [j].data [i].valTBY = this.dataset [j].data [i].y - (this.dataset [j].data [i].h / 2);
						//Update y-co ordinates
						if (this.dataset [j].data [i].h >= 0)
						{
							posY = posY - this.dataset [j].data [i].h;
						}else
						{
							negY = negY - this.dataset [j].data [i].h;
						}
						//Width
						this.dataset [j].data [i].w = colWidth;
					}
				}
			}
			//Store positive end Y and negative end Y in sums
			this.sums [i].pY = posY;
			this.sums [i].nY = negY;
		}
		//Now, store the positions of the lines
		for (i = 1; i <= this.numDS; i ++)
		{
			if (this.dataset [i].parentYAxis == "S")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//X-Position
					this.dataset [i].data [j].x = this.categories [j].x;
					//Set the y position
					this.dataset [i].data [j].y = this.getAxisPosition (this.dataset [i].data [j].value, this.config.SYMax, this.config.SYMin, this.elements.canvasBg.y, this.elements.canvasBg.toY, true, 0) + this.config.shifts.yShift;
					//Store value textbox y position
					this.dataset [i].data [j].valTBY = this.dataset [i].data [j].y;
				}
			}
		}
	}
	/**
	* allotDepths method allots the depths for various chart objects
	* to be rendered. We do this before hand, so that we can later just
	* go on rendering chart objects, without swapping.
	*/
	private function allotDepths () : Void
	{
		//Background
		this.dm.reserveDepths ("BACKGROUND", 1);
		//Click URL Handler
		this.dm.reserveDepths ("CLICKURLHANDLER", 1);
		//Background SWF
		this.dm.reserveDepths ("BGSWF", 1);
		//Canvas
		this.dm.reserveDepths ("CANVASBG", 1);
		this.dm.reserveDepths ("CANVASBASE", 1);
		//Div Lines and their labels
		this.dm.reserveDepths ("DIVLINES", (this.divLines.length * 3));
		//Caption
		this.dm.reserveDepths ("CAPTION", 1);
		//Sub-caption
		this.dm.reserveDepths ("SUBCAPTION", 1);
		//X-Axis Name
		this.dm.reserveDepths ("XAXISNAME", 1);
		//Y-Axis Name
		this.dm.reserveDepths ("YAXISNAME", 2);
		//Trend lines plot (lines and their labels)
		this.dm.reserveDepths ("TRENDLINES", this.numTrendLines);
		this.dm.reserveDepths ("TRENDVALUES", this.numTrendLines);
		//Vertical div lines
		this.dm.reserveDepths ("VLINES", this.numVLines);
		//Data Labels
		this.dm.reserveDepths ("DATALABELS", this.num);
		//Data Columns - Negative values
		this.dm.reserveDepths ("DATAPLOTNEG", this.num);
		//Zero Plane
		this.dm.reserveDepths ("ZEROPLANE", 2);
		//Data Columns - Positive Values
		this.dm.reserveDepths ("DATAPLOTPOS", this.num);
		//Data Values - Column
		this.dm.reserveDepths ("DATAVALUESCOLUMN", this.num * this.numColDS);
		//Data Sums
		this.dm.reserveDepths ("DATASUM", this.num);
		//Line Plot
		this.dm.reserveDepths ("DATAPLOTLINE", this.numLineDS);
		//Anchors
		this.dm.reserveDepths ("ANCHORS", this.numLineDS * this.num);
		//Data Values - Lines
		this.dm.reserveDepths ("DATAVALUESLINE", this.num * this.numLineDS);
		//Legend
		this.dm.reserveDepths ("LEGEND", 1);
	}
	//--------------- VISUAL RENDERING METHODS -------------------------//
	/**
	* drawHeaders method renders the following on the chart:
	* CAPTION, SUBCAPTION, XAXISNAME, YAXISNAME
	*/
	private function drawHeaders ()
	{
		//Render caption
		if (this.params.caption != "")
		{
			var captionStyleObj : Object = this.styleM.getTextStyle (this.objects.CAPTION);
			captionStyleObj.align = "center";
			captionStyleObj.vAlign = "bottom";
			var captionObj : Object = createText (false, this.params.caption, this.cMC, this.dm.getDepth ("CAPTION") , this.elements.canvasBg.x + (this.elements.canvasBg.w / 2) , this.params.chartTopMargin, 0, captionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (captionObj.tf, this.objects.CAPTION, this.macro, this.elements.canvasBg.x + (this.elements.canvasBg.w / 2) - (this.elements.caption.w / 2) , 0, this.params.chartTopMargin, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (captionObj.tf, this.objects.CAPTION);
			//Delete
			delete captionObj;
			delete captionStyleObj;
		}
		//Render sub caption
		if (this.params.subCaption != "")
		{
			var subCaptionStyleObj : Object = this.styleM.getTextStyle (this.objects.SUBCAPTION);
			subCaptionStyleObj.align = "center";
			subCaptionStyleObj.vAlign = "top";
			var subCaptionObj : Object = createText (false, this.params.subCaption, this.cMC, this.dm.getDepth ("SUBCAPTION") , this.elements.canvasBg.x + (this.elements.canvasBg.w / 2) , this.elements.canvasBg.y - this.params.captionPadding, 0, subCaptionStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (subCaptionObj.tf, this.objects.SUBCAPTION, this.macro, this.elements.canvasBg.x + (this.elements.canvasBg.w / 2) - (this.elements.subCaption.w / 2) , 0, this.elements.canvasBg.y - this.params.captionPadding - this.elements.subCaption.h, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (subCaptionObj.tf, this.objects.SUBCAPTION);
			//Delete
			delete subCaptionObj;
			delete subCaptionStyleObj;
		}
		//Render x-axis name
		if (this.params.xAxisName != "")
		{
			var xAxisNameStyleObj : Object = this.styleM.getTextStyle (this.objects.XAXISNAME);
			xAxisNameStyleObj.align = "center";
			xAxisNameStyleObj.vAlign = "bottom";
			var xAxisNameObj : Object = createText (false, this.params.xAxisName, this.cMC, this.dm.getDepth ("XAXISNAME") , this.elements.canvasBase.x + (this.elements.canvasBase.w / 2) , this.elements.canvas.toY + this.params.labelPadding + this.config.labelAreaHeight + this.params.xAxisNamePadding, 0, xAxisNameStyleObj, false, 0, 0);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (xAxisNameObj.tf, this.objects.XAXISNAME, this.macro, this.elements.canvasBase.x + (this.elements.canvasBase.w / 2) - (this.elements.subCaption.w / 2) , 0, this.elements.canvas.toY + this.config.labelAreaHeight + this.params.xAxisNamePadding, 0, 100, null, null, null);
			}
			//Apply filters
			this.styleM.applyFilters (xAxisNameObj.tf, this.objects.XAXISNAME);
			//Delete
			delete xAxisNameObj;
			delete xAxisNameStyleObj;
		}
		//Render primary y-axis name
		if (this.params.PYAxisName != "")
		{
			var yAxisNameStyleObj : Object = this.styleM.getTextStyle (this.objects.YAXISNAME);
			//Set alignment parameters
			yAxisNameStyleObj.align = "left";
			yAxisNameStyleObj.vAlign = "middle";
			//If the name is to be rotated
			if (this.params.rotateYAxisName)
			{
				//Set font as the embedded font
				yAxisNameStyleObj.font = _embeddedFont;
				//Set bold/italic to false.
				yAxisNameStyleObj.bold = false;
				yAxisNameStyleObj.italic = false;
				var yAxisNameObj : Object = createText (false, this.params.PYAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") , this.params.chartLeftMargin, this.elements.canvas.y + (this.elements.canvas.h / 2) , 270, yAxisNameStyleObj, false, 0, 0);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, this.elements.canvas.y + (this.elements.canvas.h / 2) + (this.elements.yAxisName.h / 2) , 0, 100, null, null, null);
				}
			}else
			{
				//We show horizontal name
				//Adding 1 to this.params.PYAxisNameWidth and then passing to avoid line breaks
				var yAxisNameObj : Object = createText (false, this.params.PYAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") , this.params.chartLeftMargin, this.elements.canvas.y + (this.elements.canvas.h / 2) , 0, yAxisNameStyleObj, true, this.params.PYAxisNameWidth + 1, this.elements.canvas.h);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.params.chartLeftMargin, 0, yAxisNameObj.tf._y, 0, 100, null, null, null);
				}
			}
			//Apply filters
			this.styleM.applyFilters (yAxisNameObj.tf, this.objects.YAXISNAME);
			//Delete
			delete yAxisNameObj;
			delete yAxisNameStyleObj;
		}
		//Render secondary y-axis name
		if (this.params.SYAxisName != "")
		{
			var yAxisNameStyleObj : Object = this.styleM.getTextStyle (this.objects.YAXISNAME);
			//Set alignment parameters
			yAxisNameStyleObj.align = "left";
			yAxisNameStyleObj.vAlign = "middle";
			//If the name is to be rotated
			if (this.params.rotateYAxisName)
			{
				//Set font as the embedded font
				yAxisNameStyleObj.font = _embeddedFont;
				//Set bold/italic to false.
				yAxisNameStyleObj.bold = false;
				yAxisNameStyleObj.italic = false;
				var yAxisNameObj : Object = createText (false, this.params.SYAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") + 1, this.elements.canvas.toX + this.params.yAxisValuesPadding + this.config.rightSideValueWidth + this.params.yAxisNamePadding, this.elements.canvas.y + (this.elements.canvas.h / 2) , 270, yAxisNameStyleObj, false, 0, 0);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.elements.canvas.toX + this.params.yAxisValuesPadding + this.config.rightSideValueWidth + this.params.yAxisNamePadding, 0, this.elements.canvas.y + (this.elements.canvas.h / 2) + (this.elements.yAxisName.h / 2) , 0, 100, null, null, null);
				}
			}else
			{
				//We show horizontal name
				//Adding 1 to this.params.PYAxisNameWidth and then passing to avoid line breaks
				var yAxisNameObj : Object = createText (false, this.params.SYAxisName, this.cMC, this.dm.getDepth ("YAXISNAME") + 1, this.elements.canvas.toX + this.params.yAxisValuesPadding + this.config.rightSideValueWidth + this.params.yAxisNamePadding, this.elements.canvas.y + (this.elements.canvas.h / 2) , 0, yAxisNameStyleObj, true, this.params.SYAxisNameWidth + 1, this.elements.canvas.h);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (yAxisNameObj.tf, this.objects.YAXISNAME, this.macro, this.elements.canvas.toX + this.params.yAxisValuesPadding + this.config.rightSideValueWidth + this.params.yAxisNamePadding, 0, yAxisNameObj.tf._y, 0, 100, null, null, null);
				}
			}
			//Apply filters
			this.styleM.applyFilters (yAxisNameObj.tf, this.objects.YAXISNAME);
			//Delete
			delete yAxisNameObj;
			delete yAxisNameStyleObj;
		}
		//Clear Interval
		clearInterval (this.config.intervals.headers);
	}
	/**
	* drawLabels method draws the x-axis labels based on the oarameters.
	*/
	private function drawLabels ()
	{
		var labelObj : Object;
		var labelStyleObj : Object = this.styleM.getTextStyle (this.objects.DATALABELS);
		var labelYShift : Number;
		var staggerCycle : Number = 0;
		var staggerAddFn : Number = 1;
		var depth : Number = this.dm.getDepth ("DATALABELS");
		var i : Number;
		for (i = 1; i <= this.num; i ++)
		{
			//If the label is to be shown
			if (this.categories [i].showLabel)
			{
				if (this.params.labelDisplay == "ROTATE")
				{
					//Set style bold/italic to false and font to embedded font
					labelStyleObj.font = _embeddedFont;
					labelStyleObj.bold = false;
					labelStyleObj.italic = false;
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Create text box and get height
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, this.config.labelAngle, labelStyleObj, false, 0, 0);
				} else if (this.params.labelDisplay == "WRAP")
				{
					//Case 2 (WRAP)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, 0, labelStyleObj, true, this.config.wrapLabelWidth, this.config.wrapLabelHeight);
				} else if (this.params.labelDisplay == "STAGGER")
				{
					//Case 3 (Stagger)
					//Set alignment
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					//Need to get cyclic position for staggered textboxes
					//Matrix formed is of 2*this.params.staggerLines - 2 rows
					var pos : Number = i % (2 * this.params.staggerLines - 2);
					//Last element needs to be reset
					pos = (pos == 0) ? (2 * this.params.staggerLines - 2) : pos;
					//Cyclic iteration
					pos = (pos > this.params.staggerLines) ? (this.params.staggerLines - (pos % this.params.staggerLines)) : pos;
					//Get position to 0 base
					pos --;
					//Shift accordingly
					var labelYShift : Number = this.config.maxLabelHeight * pos;
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding + labelYShift, 0, labelStyleObj, false, 0, 0);
				} else 
				{
					//Render normal label
					labelStyleObj.align = "center";
					labelStyleObj.vAlign = "bottom";
					labelObj = createText (false, this.categories [i].label, this.cMC, depth, this.categories [i].x, this.elements.canvas.toY + this.params.labelPadding, 0, labelStyleObj, false, 0, 0);
				}
				//Apply filter
				this.styleM.applyFilters (labelObj.tf, this.objects.DATALABELS);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (labelObj.tf, this.objects.DATALABELS, this.macro, labelObj.tf._x, 0, labelObj.tf._y, 0, 100, null, null, null);
				}
				//Increase depth
				depth ++;
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.labels);
	}
	/**
	* drawColumns method draws the columns on the chart
	*/
	private function drawColumns ()
	{
		//Variables
		var colMC : MovieClip, pStackMC : MovieClip, nStackMC : MovieClip;
		var colIns : Column3D;
		var posDepth : Number = this.dm.getDepth ("DATAPLOTPOS");
		var negDepth : Number = this.dm.getDepth ("DATAPLOTNEG");
		var depth : Number;
		var i : Number;
		var j : Number;
		var animY : Number;
		//Create function storage containers for Delegate functions
		var fnRollOver : Function, fnClick : Function;
		//Rendered Column Count
		var renderedColCount : Number = 0;
		//Iterate through all columns
		for (i = 1; i <= this.num; i ++)
		{
			//For each data index, we now create two movie clips:
			//PosStack_i, NegStack_i (both on conditional basis)
			//Create the positive stack movie clip (if required).
			if (this.sums [i].pSum != undefined)
			{
				pStackMC = this.cMC.createEmptyMovieClip ("PosStack_" + i, posDepth);
				posDepth ++;
			}
			if (this.sums [i].nSum != undefined)
			{
				nStackMC = this.cMC.createEmptyMovieClip ("NegStack_" + i, negDepth);
				negDepth ++;
			}
			//Shift both the movie clips down so that columns can be positioned
			//inside at 0 y - for proper yScale animation
			pStackMC._y = this.config.basePlanePos + this.config.shifts.yShift;
			nStackMC._y = this.config.basePlanePos + this.config.shifts.yShift;
			//Reset column count
			renderedColCount = 0;
			//Now, iterate through each column to create the stacked column.
			for (j = 1; j <= this.numDS; j ++)
			{
				//If the column is defined and is column
				if (this.dataset [j].parentYAxis == "P" && this.dataset [j].data [i].isDefined)
				{
					//Increase count
					renderedColCount ++;
					depth = this.dataset [j].data [i].depth;
					//Based on whether the column is positive or negative,
					//create an empty movie clip for this column
					if (this.dataset [j].data [i].value >= 0)
					{
						colMC = pStackMC.createEmptyMovieClip ("Column_" + i + "_" + j, depth);
					}else
					{
						colMC = nStackMC.createEmptyMovieClip ("Column_" + i + "_" + j, depth);
					}
					//Create column instance
					//We're adjusting Y position of the column inside stacked movie clip
					//so that the first column (both positive and negative) originate at 0 y
					//and the rest on referential Y. We do not alter X.
					colIns = new Column3D (colMC, this.dataset [j].data [i].x, this.dataset [j].data [i].y - this.config.basePlanePos - this.config.shifts.yShift, this.config.shifts.wFront, this.dataset [j].data [i].h, this.config.shifts.xShift, this.config.shifts.yShift, this.dataset [j].data [i].color, this.params.showPlotBorder, this.params.plotBorderColor, this.params.plotBorderAlpha);
					//Draw the column
					colIns.draw (this.params.use3DLighting);
					//Set the alpha of entire column
					colMC._alpha = this.dataset [j].data [i].alpha;
					//Event handlers for tool tip
					if (this.params.showToolTip)
					{
						//Create Delegate for roll over function dataOnRollOver
						fnRollOver = Delegate.create (this, dataOnRollOver);
						//Set the index
						fnRollOver.dsindex = j;
						fnRollOver.index = i;
						//Assing the delegates to movie clip handler
						colMC.onRollOver = fnRollOver;
						//Set roll out and mouse move too.
						colMC.onRollOut = colMC.onReleaseOutside = Delegate.create (this, dataOnRollOut);
						colMC.onMouseMove = Delegate.create (this, dataOnMouseMove);
					}
					//Click handler for links - only if link for this column has been defined and click URL
					//has not been defined.
					if (this.dataset [j].data [i].link != "" && this.dataset [j].data [i].link != undefined && this.params.clickURL == "")
					{
						//Create delegate function
						fnClick = Delegate.create (this, dataOnClick);
						//Set index
						fnClick.dsindex = j;
						fnClick.index = i;
						//Assign
						colMC.onRelease = fnClick;
					}
					else
					{
						//Do not use hand cursor
						colMC.useHandCursor = (this.params.clickURL == "") ?false : true;
					}
				}
			}
			//Apply animation
			if (this.params.animation && renderedColCount > 0)
			{
				//For Positive stack
				if (this.sums [i].pSum != undefined)
				{
					//We animate yScale only if |height| > this.config.shifts.yShift*1.5
					//if ((Math.abs(pStackMC._height) - this.config.shifts.yShift)>(this.config.shifts.yShift*1.5)){
					if (Math.abs (pStackMC._height) > (this.config.shifts.yShift * 1.5))
					{
						animY = 100;
					}
					else
					{
						animY = null;
					}
					this.styleM.applyAnimation (pStackMC, this.objects.DATAPLOTCOLUMN, this.macro, this.dataset [j].data [i].x, 0, this.dataset [j].data [i].y, 0, 100, 100, animY, null);
				}
				//Negative Stack
				if (this.sums [i].nSum != undefined)
				{
					//We animate yScale only if |height| > this.config.shifts.yShift*1.5
					if (Math.abs (nStackMC._height) > (this.config.shifts.yShift * 1.5))
					{
						animY = 100;
					}
					else
					{
						animY = null;
					}
					this.styleM.applyAnimation (nStackMC, this.objects.DATAPLOTCOLUMN, this.macro, this.dataset [j].data [i].x, 0, this.dataset [j].data [i].y, 0, 100, 100, animY, null);
				}
			}
			//Apply filters (only if column count > 0)
			if (renderedColCount > 0)
			{
				this.styleM.applyFilters (pStackMC, this.objects.DATAPLOTCOLUMN);
				this.styleM.applyFilters (nStackMC, this.objects.DATAPLOTCOLUMN);
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.plot);
	}
	/**
	* drawLineChart method draws the lines on the chart
	*/
	private function drawLineChart () : Void 
	{
		/**
		* The movie clip structure for each line (dataset) would be :
		* |- Holder
		* |- |- Chart
		* We create child movie clip as we need to animate xscale
		* and y scale. So, we need to position Chart Movie clip at 0,0
		* inside holder movie clip and then readjust Holder movie clip's
		* X and Y Position as per chart's canvas.
		*/
		var m : Number;
		var depth : Number = this.dm.getDepth ("DATAPLOTLINE");
		for (m = 1; m <= this.numDS; m ++)
		{
			//If it's line dataset
			if (this.dataset [m].parentYAxis == "S")
			{
				//Create holder movie clip
				var holderMC : MovieClip = this.cMC.createEmptyMovieClip ("ChartHolder_" + m, depth);
				//Create chart movie clip inside holder movie clip
				var chartMC : MovieClip = holderMC.createEmptyMovieClip ("Chart", 1);
				//Loop variables
				var i, j;
				//Variables to store the max and min Y positions
				var maxY : Number, minY : Number;
				//Find the index of the first defined data
				//Initialize with (this.num+1) so that if no defined data is found,
				//next loop automatically terminates
				var firstIndex : Number = this.num + 1;
				//Storage container for next plot index
				var nxt : Number;
				for (i = 1; i < this.num; i ++)
				{
					if (this.dataset [m].data [i].isDefined)
					{
						firstIndex = i;
						break;
					}
				}
				//Now, we draw the lines inside chart
				for (i = firstIndex; i < this.num; i ++)
				{
					//We continue only if this data index is defined
					if (this.dataset [m].data [i].isDefined)
					{
						//Get next Index
						nxt = i + 1;
						//Now, if next index is not defined, we can have two cases:
						//1. Draw gap between this data and next data.
						//2. Connect the next index which could be found as defined.
						//Case 1. If connectNullData is set to false and next data is not
						//defined. We simply continue to next value of the loop
						if (this.params.connectNullData == false && this.dataset [m].data [nxt].isDefined == false)
						{
							//Discontinuous plot. So ignore and move to next.
							continue;
						}
						//Now, if nxt data is undefined, we need to find the index of the post data
						//which is not undefined
						if (this.dataset [m].data [nxt].isDefined == false)
						{
							//Initiate nxt as -1, so that we can later break if no next defined data
							//could be found.
							nxt = - 1;
							for (j = i + 1; j <= this.num; j ++)
							{
								if (this.dataset [m].data [j].isDefined == true)
								{
									nxt = j;
									break;
								}
							}
							//If nxt is still -1, we break
							if (nxt == - 1)
							{
								break;
							}
						}
						//Set line style
						chartMC.lineStyle (this.dataset [m].lineThickness, parseInt (this.dataset [m].data [i].color, 16) , this.dataset [m].data [i].alpha);
						//Now, based on whether we've to draw a normal or dashed line, we draw it
						if (this.dataset [m].data [i].dashed)
						{
							//Draw a dashed line
							DrawingExt.dashTo (chartMC, this.dataset [m].data [i].x, this.dataset [m].data [i].y, this.dataset [m].data [nxt].x, this.dataset [m].data [nxt].y, this.dataset [m].lineDashLen, this.dataset [m].lineDashGap);
						} else 
						{
							//Move to the point
							chartMC.moveTo (this.dataset [m].data [i].x, this.dataset [m].data [i].y);
							//Draw point to next line
							chartMC.lineTo (this.dataset [m].data [nxt].x, this.dataset [m].data [nxt].y);
						}
						//Get maxY and minY
						maxY = (maxY == undefined || (this.dataset [m].data [i].y > maxY)) ? this.dataset [m].data [i].y : maxY;
						minY = (minY == undefined || (this.dataset [m].data [i].y < minY)) ? this.dataset [m].data [i].y : minY;
						//Update loop index (required when connectNullData is true and there is
						//a sequence of empty sets.) Since we've already found the "next" defined
						//data, we update loop to that to optimize.
						i = nxt - 1;
					}
				}
				//Now, we need to adjust the chart movie clip to 0,0 position as center
				chartMC._x = - (this.elements.canvas.w / 2) - this.elements.canvas.x;
				chartMC._y = - (maxY) + ((maxY - minY) / 2);
				//Set the position of holder movie clip now
				holderMC._x = (this.elements.canvas.w / 2) + this.elements.canvas.x;
				holderMC._y = (maxY) - ((maxY - minY) / 2);
				//Apply filter
				this.styleM.applyFilters (holderMC, this.objects.DATAPLOTLINE);
				//Apply animation
				if (this.params.animation)
				{
					this.styleM.applyAnimation (holderMC, this.objects.DATAPLOTLINE, this.macro, holderMC._x, 0, holderMC._y, 0, 100, 100, 100, null);
				}
				//Increment depth
				depth ++;
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.plotLine);
	}
	/**
	* drawAnchors method draws the anchors on the chart
	*/
	private function drawAnchors () : Void 
	{
		//Variables
		var anchorMC : MovieClip;
		var depth : Number = this.dm.getDepth ("ANCHORS");
		var i : Number, j : Number;
		//Create function storage containers for Delegate functions
		var fnRollOver : Function, fnClick : Function;
		//Iterate through all columns
		for (i = 1; i <= this.numDS; i ++)
		{
			//If it's line dataset
			if (this.dataset [i].drawAnchors && this.dataset [i].parentYAxis == "S")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//If defined
					if (this.dataset [i].data [j].isDefined)
					{
						//Create an empty movie clip for this anchor
						anchorMC = this.cMC.createEmptyMovieClip ("Anchor_" + i + "_" + j, depth);
						//Set the line style and fill
						anchorMC.lineStyle (this.dataset [i].data [j].anchorBorderThickness, parseInt (this.dataset [i].data [j].anchorBorderColor, 16) , 100);
						anchorMC.beginFill (parseInt (this.dataset [i].data [j].anchorBgColor, 16) , this.dataset [i].data [j].anchorBgAlpha);
						//Draw the polygon
						DrawingExt.drawPoly (anchorMC, 0, 0, this.dataset [i].data [j].anchorSides, this.dataset [i].data [j].anchorRadius, 90);
						//Set the x and y Position
						anchorMC._x = this.dataset [i].data [j].x;
						anchorMC._y = this.dataset [i].data [j].y;
						//Set the alpha of entire anchor
						anchorMC._alpha = this.dataset [i].data [j].anchorAlpha;
						//Apply animation
						if (this.params.animation)
						{
							this.styleM.applyAnimation (anchorMC, this.objects.ANCHORS, this.macro, anchorMC._x, 0, anchorMC._y, 0, this.dataset [i].data [j].anchorAlpha, 100, 100, null);
						}
						//Apply filters
						this.styleM.applyFilters (anchorMC, this.objects.ANCHORS);
						//Event handlers for tool tip
						if (this.params.showToolTip)
						{
							//Create Delegate for roll over function dataOnRollOver
							fnRollOver = Delegate.create (this, dataOnRollOver);
							//Set the index
							fnRollOver.dsindex = i;
							fnRollOver.index = j;
							//Assing the delegates to movie clip handler
							anchorMC.onRollOver = fnRollOver;
							//Set roll out and mouse move too.
							anchorMC.onRollOut = anchorMC.onReleaseOutside = Delegate.create (this, dataOnRollOut);
						}
						//Click handler for links - only if link for this anchor has been defined and click URL
						//has not been defined.
						if (this.dataset [i].data [j].link != "" && this.dataset [i].data [j].link != undefined && this.params.clickURL == "")
						{
							//Create delegate function
							fnClick = Delegate.create (this, dataOnClick);
							//Set index
							fnClick.dsindex = i;
							fnClick.index = j;
							//Assign
							anchorMC.onRelease = fnClick;
						} else 
						{
							//Do not use hand cursor
							anchorMC.useHandCursor = (this.params.clickURL == "") ? false : true;
						}
						//Increase depth
						depth ++;
					}
				}
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.anchors);
	}
	/**
	* drawLineValues method draws the values on the chart for the lines.
	*/
	private function drawLineValues () : Void 
	{
		//Get value text style
		var valueStyleObj : Object = this.styleM.getTextStyle (this.objects.DATAVALUES);
		//Individual properties
		var isBold : Boolean = valueStyleObj.bold;
		var isItalic : Boolean = valueStyleObj.italic;
		var font : String = valueStyleObj.font;
		var angle : Number = 0;
		//Container object
		var valueObj : MovieClip;
		//Depth
		var depth : Number = this.dm.getDepth ("DATAVALUESLINE");
		//Loop var
		var i : Number, j : Number;
		var yPos : Number;
		var align : String, vAlign : String;
		////Iterate through all points
		for (i = 1; i <= this.numDS; i ++)
		{
			//If it's line dataset
			if (this.dataset [i].parentYAxis == "S")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//If defined and value is to be shown
					if (this.dataset [i].data [j].isDefined && this.dataset [i].data [j].showValue)
					{
						//Get the y position based on next data's position
						if (i == 1)
						{
							//For first point, we show the value on top
							vAlign = "top";
							yPos = this.dataset [i].data [j].valTBY - this.params.valuePadding;
						} else 
						{
							//If this data value is more than that of previous one, we show textbox above
							if (this.dataset [i].data [j].value >= this.dataset [i].data [j - 1].value)
							{
								//Above
								vAlign = "top";
								yPos = this.dataset [i].data [j].valTBY - this.params.valuePadding;
							} else 
							{
								//Below
								vAlign = "bottom";
								yPos = this.dataset [i].data [j].valTBY + this.params.valuePadding;
							}
						}
						//Align position
						align = "center";
						//Convey alignment to rendering object
						valueStyleObj.align = align;
						valueStyleObj.vAlign = vAlign;
						//Now, if the labels are to be rotated
						if (this.params.rotateValues)
						{
							valueStyleObj.bold = false;
							valueStyleObj.italic = false;
							valueStyleObj.font = _embeddedFont;
							angle = 270;
						} else 
						{
							//Normal horizontal label - Store original properties
							valueStyleObj.bold = isBold;
							valueStyleObj.italic = isItalic;
							valueStyleObj.font = font;
							angle = 0;
						}
						valueObj = createText (false, this.dataset [i].data [j].displayValue, this.cMC, depth, this.dataset [i].data [j].x, yPos, angle, valueStyleObj, false, 0, 0);
						//Next, we adjust those labels are falling out of top canvas area
						if (((yPos - valueObj.height) <= this.elements.canvas.y))
						{
							//Data value is colliding with the upper side of canvas. So we need to place it within
							//the area
							if ( ! this.params.rotateValues)
							{
								valueObj.tf._y = yPos + (2 * this.params.valuePadding);
							} else 
							{
								valueObj.tf._y = yPos + (2 * this.params.valuePadding) + valueObj.height;
							}
						}
						//Now, we adjust those labels are falling out of bottom canvas area
						if (((yPos + valueObj.height) >= this.elements.canvas.toY))
						{
							//Data value is colliding with the lower side of canvas. So we need to place it within
							//the area
							if ( ! this.params.rotateValues)
							{
								valueObj.tf._y = yPos - (2 * this.params.valuePadding) - valueObj.height;
							} else 
							{
								valueObj.tf._y = yPos - (2 * this.params.valuePadding);
							}
						}
						//Apply filter
						this.styleM.applyFilters (valueObj.tf, this.objects.DATAVALUES);
						//Apply animation
						if (this.params.animation)
						{
							this.styleM.applyAnimation (valueObj.tf, this.objects.DATAVALUES, this.macro, valueObj.tf._x, 0, valueObj.tf._y, 0, 100, null, null, null);
						}
						//Increase depth
						depth ++;
					}
				}
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.dataValuesLine);
	}
	/**
	*  drawColumnValues method draws the values on the chart.
	*/
	private function drawColumnValues () : Void
	{
		//Get value text style
		var valueStyleObj : Object = this.styleM.getTextStyle (this.objects.DATAVALUES);
		//Individual properties
		var isBold : Boolean = valueStyleObj.bold;
		var isItalic : Boolean = valueStyleObj.italic;
		var font : String = valueStyleObj.font;
		var angle : Number = 0;
		//Container object
		var valueObj : MovieClip;
		//Depth
		var depth : Number = this.dm.getDepth ("DATAVALUESCOLUMN");
		//Loop var
		var i : Number;
		var j : Number;
		var yPos : Number;
		var xPos : Number;
		var align : String, vAlign : String;
		////Iterate through all columns
		for (i = 1; i <= this.numDS; i ++)
		{
			if (this.dataset [i].parentYAxis == "P")
			{
				for (j = 1; j <= this.num; j ++)
				{
					//If defined and value is to be shown
					if (this.dataset [i].data [j].isDefined && this.dataset [i].data [j].showValue)
					{
						//Align position
						align = "center";
						//Vertical alignment position of the value box
						vAlign = "middle";
						//X-position - at center of column
						xPos = this.dataset [i].data [j].x;
						yPos = (this.dataset [i].data [j].valTBY);
						//Convey alignment to rendering object
						valueStyleObj.align = align;
						valueStyleObj.vAlign = vAlign;
						//Now, if the labels are to be rotated
						if (this.params.rotateValues)
						{
							valueStyleObj.bold = false;
							valueStyleObj.italic = false;
							valueStyleObj.font = _embeddedFont;
							angle = 270;
						}else
						{
							//Normal horizontal label - Store original properties
							valueStyleObj.bold = isBold;
							valueStyleObj.italic = isItalic;
							valueStyleObj.font = font;
							angle = 0;
						}
						valueObj = createText (false, this.dataset [i].data [j].displayValue, this.cMC, depth, xPos , yPos, angle, valueStyleObj, false, 0, 0);
						//Apply filter
						this.styleM.applyFilters (valueObj.tf, this.objects.DATAVALUES);
						//Apply animation
						if (this.params.animation)
						{
							this.styleM.applyAnimation (valueObj.tf, this.objects.DATAVALUES, this.macro, valueObj.tf._x, 0, valueObj.tf._y, 0, 100, null, null, null);
						}
						//Increase depth
						depth ++;
					}
				}
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.dataValues);
	}
	/**
	* drawSum method draws the sum of values on the chart.
	*/
	private function drawSum () : Void
	{
		if (this.params.showSum)
		{
			//Get value text style
			var valueStyleObj : Object = this.styleM.getTextStyle (this.objects.DATAVALUES);
			//Individual properties
			var isBold : Boolean = valueStyleObj.bold;
			var isItalic : Boolean = valueStyleObj.italic;
			var font : String = valueStyleObj.font;
			var angle : Number = 0;
			//Container object
			var valueObj : MovieClip;
			//Depth
			var depth : Number = this.dm.getDepth ("DATASUM");
			//Loop var
			var i : Number;
			var xPos : Number, yPos : Number;
			var align : String, vAlign : String;
			////Iterate through all indexs
			for (i = 1; i <= this.num; i ++)
			{
				//If defined and value is to be shown
				if (this.sums [i].sum != 0)
				{
					//Align position
					align = "center";
					//Vertical Alignment position
					vAlign = (this.sums [i].sum < 0) ?"bottom" : "top";
					//X-position
					xPos = (this.sums [i].sum >= 0) ? (this.categories [i].x + this.config.shifts.xShift) : (this.categories [i].x);
					//Get the y position
					yPos = this.config.basePlanePos + ((this.sums [i].sum < 0) ? (this.sums [i].nY + this.config.shifts.yShift) : (this.sums [i].pY));
					//Convey alignment to rendering object
					valueStyleObj.align = align;
					valueStyleObj.vAlign = vAlign;
					//Now, if the labels are to be rotated
					if (this.params.rotateValues)
					{
						valueStyleObj.bold = false;
						valueStyleObj.italic = false;
						valueStyleObj.font = _embeddedFont;
						angle = 270;
					}else
					{
						//Normal horizontal label - Store original properties
						valueStyleObj.bold = isBold;
						valueStyleObj.italic = isItalic;
						valueStyleObj.font = font;
						angle = 0;
					}
					valueObj = createText (false, this.sums [i].displayValue, this.cMC, depth, xPos , yPos, angle, valueStyleObj, false, 0, 0);
					//Apply filter
					this.styleM.applyFilters (valueObj.tf, this.objects.DATAVALUES);
					//Apply animation
					if (this.params.animation)
					{
						this.styleM.applyAnimation (valueObj.tf, this.objects.DATAVALUES, this.macro, valueObj.tf._x, 0, valueObj.tf._y, 0, 100, null, null, null);
					}
					//Increase depth
					depth ++;
				}
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.dataSum);
	}
	/**
	* drawLegend method renders the legend
	*/
	private function drawLegend () : Void
	{
		if (this.params.showLegend)
		{
			this.lgnd.render ();
			//Apply filter
			this.styleM.applyFilters (lgndMC, this.objects.LEGEND);
			//Apply animation
			if (this.params.animation)
			{
				this.styleM.applyAnimation (lgndMC, this.objects.LEGEND, this.macro, null, 0, null, 0, 100, null, null, null);
			}
		}
		//Clear interval
		clearInterval (this.config.intervals.legend);
	}
	/**
	* setContextMenu method sets the context menu for the chart.
	* For this chart, the context items are "Print Chart".
	*/
	private function setContextMenu () : Void
	{
		var chartMenu : ContextMenu = new ContextMenu ();
		chartMenu.hideBuiltInItems ();
		//Create a print chart contenxt menu item
		var printCMI : ContextMenuItem = new ContextMenuItem ("Print Chart", Delegate.create (this, printChart));
		//Push print item.
		chartMenu.customItems.push (printCMI);
		if (this.params.showFCMenuItem){
			//Push "About FusionCharts" Menu Item
			chartMenu.customItems.push(super.returnAbtMenuItem());		
		}
		//Assign the menu to cMC movie clip
		this.cMC.menu = chartMenu;
	}
	// -------------------- EVENT HANDLERS --------------------//
	/**
	* dataOnRollOver is the delegat-ed event handler method that'll
	* be invoked when the user rolls his mouse over a column.
	* This function is invoked, only if the tool tip is to be shown.
	* Here, we show the tool tip.
	*/
	private function dataOnRollOver () : Void
	{
		//Index of column is stored in arguments.caller.index
		var dsindex : Number = arguments.caller.dsindex;
		var index : Number = arguments.caller.index;
		//Set tool tip text
		this.tTip.setText (this.dataset [dsindex].data [index].toolText);
		//Show the tool tip
		this.tTip.show ();
	}
	/**
	* dataOnRollOut method is invoked when the mouse rolls out
	* of column. We just hide the tool tip here.
	*/
	private function dataOnRollOut () : Void
	{
		//Hide the tool tip
		this.tTip.hide ();
	}
	/*
	* dataOnMouseMove is called when the mouse position has changed
	* over column. We reposition the tool tip.
	*/
	private function dataOnMouseMove () : Void
	{
		//Reposition the tool tip only if it's in visible state
		if (this.tTip.visible ())
		{
			this.tTip.rePosition ();
		}
	}
	/**
	* dataOnClick is invoked when the user clicks on a column (if link
	* has been defined). We invoke the required link.
	*/
	private function dataOnClick () : Void
	{
		//Index of column is stored in arguments.caller.index
		var dsindex : Number = arguments.caller.dsindex;
		var index : Number = arguments.caller.index;
		//Invoke the link
		super.invokeLink (this.dataset [dsindex].data [index].link);
	}
	/**
	* reInit method re-initializes the chart. This method is basically called
	* when the user changes chart data through JavaScript. In that case, we need
	* to re-initialize the chart, set new XML data and again render.
	*/
	public function reInit () : Void
	{
		//Invoke super class's reInit
		super.reInit ();
		//Now initialize things that are pertinent to this class
		//but not defined in super class.
		this.categories = new Array ();
		this.dataset = new Array ();
		//Initialize the number of data elements present
		this.numDS = 0;
		this.numColDS = 0;
		this.numLineDS = 0;
		this.num = 0;
		this.lgnd.reset ();
		this.negativePresent = false;
		this.positivePresent = false;
		//Array to store sum of data sets
		this.sums = new Array ();
		this.sumStored = false;
	}
	/**
	* remove method removes the chart by clearing the chart movie clip
	* and removing any listeners.
	*/
	public function remove () : Void 
	{
		super.remove ();
		//Remove class pertinent objects
		this.lgnd.destroy ();
		lgndMC.removeMovieClip ();
	}
}
